swift-lang
4
总安装量
3
周安装量
#50300
全站排名
安装命令
npx skills add https://github.com/makgunay/claude-swift-skills --skill swift-lang
Agent 安装分布
opencode
3
claude-code
3
codex
3
cursor
3
gemini-cli
2
github-copilot
2
Skill 文档
Swift 6.2 Language Patterns
Corrective guide for Swift code generation. Swift 6.2 fundamentally changed the concurrency model â most LLM training data reflects the old model.
Critical Constraints
- â DO NOT use
ObservableObject+@Publishedfor macOS 14+ / iOS 17+ â â Use@Observablemacro (import Observation) - â DO NOT use
@StateObjectâ â Use@Statewith@Observableclasses - â DO NOT use
@ObservedObjectâ â Use@Bindablefor bindings, or just pass the object - â DO NOT use
@EnvironmentObjectâ â Use@Environmentwith custom key - â DO NOT assume async functions always hop off the actor â â In Swift 6.2, async functions run on the caller’s actor by default
- â DO NOT use
Task.detachedto get background execution â â Use@concurrentattribute on the function - â DO NOT add
@Sendableto everything to silence warnings â â Use default MainActor isolation mode, opt out withnonisolated - â DO NOT use
DispatchQueue.main.asyncfor main thread work â â Use@MainActororMainActor.run {} - â DO NOT use
DispatchQueue.global().asyncfor background work â â Use@concurrentfunctions withawait - â DO NOT create
NavigationViewâ â UseNavigationSplitVieworNavigationStack
Decision Tree: Concurrency Model
Starting a new project or file?
âââ Is this an app/script/executable target?
â âââ YES â Enable default MainActor isolation (recommended)
â âââ All code is @MainActor by default
â âââ No data-race errors for single-threaded code
â âââ Use nonisolated + @concurrent for background work
âââ Is this a library/framework?
â âââ YES â Use explicit annotations (@MainActor, nonisolated, Sendable)
â
Need background execution?
âââ Use @concurrent on the function
âââ Mark the containing type as nonisolated
âââ Add async to the function signature
âââ Callers must await the result
Decision Tree: Observable Pattern
Need observable state in a view?
âââ macOS 14+ / iOS 17+ target?
â âââ YES â Use @Observable macro
â â âââ View owns it? â @State private var model = MyModel()
â â âââ View receives it? â just use the parameter (no wrapper needed)
â â âââ Need binding? â @Bindable var model
â â âââ Environment? â @Environment(MyModel.self) var model
â âââ NO (older targets) â Use ObservableObject + @Published
â âââ View owns it? â @StateObject
â âââ View receives it? â @ObservedObject
â âââ Environment? â @EnvironmentObject
Verified Patterns
See references/concurrency.md for comprehensive Swift 6.2 concurrency patterns.
See references/performance.md for InlineArray, Span, and memory optimization.
Pattern: @Observable Class (Modern)
import SwiftUI
import Observation
@Observable
class StickerModel {
var stickers: [Sticker] = []
var isLoading = false
func loadStickers() async {
isLoading = true
stickers = await StickerService.fetch()
isLoading = false
}
}
struct StickerListView: View {
@State private var model = StickerModel() // NOT @StateObject
var body: some View {
List(model.stickers) { sticker in
StickerRow(sticker: sticker)
}
.task { await model.loadStickers() }
}
}
// Passing to child â no wrapper needed
struct StickerRow: View {
var sticker: Sticker // plain property, NOT @ObservedObject
var body: some View {
Text(sticker.name)
}
}
// When child needs to mutate
struct StickerEditor: View {
@Bindable var model: StickerModel // NOT @ObservedObject
var body: some View {
TextField("Name", text: $model.stickers[0].name)
}
}
Pattern: Environment with @Observable
import SwiftUI
// Define environment key
struct AppModelKey: EnvironmentKey {
static let defaultValue = AppModel()
}
extension EnvironmentValues {
var appModel: AppModel {
get { self[AppModelKey.self] }
set { self[AppModelKey.self] = newValue }
}
}
// Inject
@main
struct MyApp: App {
@State private var appModel = AppModel()
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.appModel, appModel)
}
}
}
// Consume
struct ContentView: View {
@Environment(\.appModel) private var appModel
var body: some View { /* use appModel */ }
}
Pattern: Default MainActor Isolation (Swift 6.2)
// With default MainActor isolation enabled in build settings,
// everything is @MainActor by default. No annotations needed.
final class StickerLibrary {
static let shared = StickerLibrary() // Safe â implicitly @MainActor
var stickers: [Sticker] = [] // Safe â on main actor
}
final class StickerModel {
let photoProcessor = PhotoProcessor()
func extractSticker(_ item: PhotosPickerItem) async throws -> Sticker? {
guard let data = try await item.loadTransferable(type: Data.self) else {
return nil
}
// No data-race error in Swift 6.2 â runs on caller's actor
return await photoProcessor.extractSticker(data: data, with: item.itemIdentifier)
}
}
Pattern: @concurrent for Background Work
// To explicitly run work OFF the main actor, use @concurrent
nonisolated struct PhotoProcessor {
@concurrent
func process(data: Data) async -> ProcessedPhoto? {
// This runs on the concurrent thread pool, NOT the main actor
// Heavy image processing here
return ProcessedPhoto(data: data)
}
}
// Caller â must await
let processor = PhotoProcessor()
let result = await processor.process(data: imageData)
Pattern: Isolated Conformances
protocol Exportable {
func export()
}
// Mark the conformance as @MainActor â safe because compiler
// ensures it's only used on the main actor
extension StickerModel: @MainActor Exportable {
func export() {
photoProcessor.exportAsPNG() // Can access MainActor state
}
}
// This works â ImageExporter is also on MainActor
@MainActor
struct ImageExporter {
var items: [any Exportable]
mutating func add(_ item: StickerModel) {
items.append(item) // OK â same actor isolation
}
}
Common Mistakes & Fixes
| Mistake | Fix |
|---|---|
class MyModel: ObservableObject with @Published |
@Observable class MyModel â remove @Published, remove protocol |
@StateObject var model = MyModel() |
@State private var model = MyModel() |
@ObservedObject var model: MyModel |
var model: MyModel (or @Bindable for bindings) |
@EnvironmentObject var model: MyModel |
@Environment(MyModel.self) var model or custom key |
Task.detached { await heavy() } |
Mark heavy() as @concurrent nonisolated |
DispatchQueue.global().async { } |
@concurrent func doWork() async { } |
static let shared causes Sendable warning |
Enable default MainActor isolation, or add @MainActor |
Adding @Sendable everywhere |
Use actor isolation instead â @MainActor or explicit actors |
await MainActor.run { } inside already-MainActor code |
Just call directly â already on MainActor |
Build Settings for Swift 6.2
Enable approachable concurrency in Xcode Build Settings â Swift Compiler – Concurrency:
- Default Actor Isolation:
MainActor(infer @MainActor by default) - Strict Concurrency Checking:
complete
Or in Package.swift:
.target(
name: "MyTarget",
swiftSettings: [
.defaultIsolation(MainActor.self)
]
)