swift-lang
Swift 6 language and tooling - concurrency model, Sendable, actors, replacing DispatchQueue and completion handlers with async/await, XCTest basics, and xcodebuild. Use for Swift code that is not a SwiftUI view. For SwiftUI architecture and view-layer testing, see `swiftui-lang`.
- License 许可
- MIT
- 最近更新
- 2026-11-14
- Stars
- ★ 1
- Forks
- 0
01 前言 Front Matter
- name
- swift-lang
- description
- Swift 6 language and tooling - concurrency model, Sendable, actors, replacing DispatchQueue and completion handlers with async/await, XCTest basics, and xcodebuild. Use for Swift code that is not a SwiftUI view. For SwiftUI architecture and view-layer testing, see `swiftui-lang`.
02 资源文件 2
- 参考文档evals/eval_queries.json1.0 KB
- 参考文档evals/evals.json3.5 KB
03 SKILL.md 正文
Swift Development
For SwiftUI-specific architecture (ViewModel extraction, DI, ViewInspector, snapshot testing, coverage targets by layer), load the swiftui-lang skill.
Swift 6 Concurrency
Swift 6 enforces data isolation at compile time. Every type must be either Sendable or confined to an actor.
Actors isolate mutable state:
actor MyService {
private var cache: [String: Data] = [:]
func store(_ data: Data, for key: String) {
cache[key] = data
}
func fetch(key: String) -> Data? {
cache[key]
}
}
Callers outside the actor await its methods; the hop onto the actor makes them asynchronous without marking them async.
@MainActor for UI-bound types:
@MainActor
final class ViewModel: ObservableObject {
@Published var items: [Item] = []
}
Sendable for types crossing actor boundaries — must be value types or immutable:
struct Config: Sendable {
let baseURL: URL
let timeout: TimeInterval
}
Rules:
- Prefer value types (
struct) over reference types (class) forSendableconformance - Mark
@Observabletypes as@MainActorwhen they drive UI - Use
async/await— avoidDispatchQueueand callback chains - Never use
nonisolated(unsafe)without a clear documented reason
Enforce strict concurrency at compile time
Manual review cannot catch every missed @Sendable on a closure handed to an Apple SDK that dispatches on a background queue. The only durable enforcement is the build flag:
// Package.swift
.target(
name: "App",
swiftSettings: [.enableExperimentalFeature("StrictConcurrency=complete")]
)
Until the project compiles cleanly under StrictConcurrency=complete, treat every closure literal written inside a @MainActor scope as a latent EXC_BREAKPOINT — see swiftui-lang for the per-call-site rule.
Pick one async primitive
DispatchQueue.main.asyncAfter, Task.sleep(nanoseconds:), Timer.scheduledTimer, and bare GCD coexisting in the same codebase is a smell. Default to async/await; reach for Timer only for periodic UI ticks. New code should not introduce GCD.
Task.sleep used to wait for "something to be ready" (connect, callback drain, settle) is a race-condition workaround, not coordination. It will go flaky under load and mask the next race. Replace with an explicit signal: a continuation, an AsyncStream, or a state observer.
Error handling — try? is a regression amplifier
try? converts loud failures into silent ones. The user sees "nothing happened" and there is nothing to debug. Reserve it for cases where the failure genuinely has no consequence (e.g. best-effort cache prime). For anything user-visible — git, subprocess, filesystem, network — surface the error:
// Bad — silent
let branches = try? await git.listBranches()
// Good — log and propagate or present
do {
let branches = try await git.listBranches()
...
} catch {
logger.error("git listBranches failed: \(error)")
throw error // or surface to the user
}
Testing with XCTest
final class MyServiceTests: XCTestCase {
func testFetch_AfterStore_ReturnsStoredData() async {
let service = MyService()
let data = Data("value".utf8)
await service.store(data, for: "key")
let result = await service.fetch(key: "key")
XCTAssertEqual(result, data)
}
}
Rules:
- Test names describe the scenario:
test<Subject>_<Condition>_<ExpectedResult> - Async tests are
async(addthrowswhen the code under test throws) — noXCTestExpectationfor async work - Create shared fixtures in
setUp()and release them intearDown(), not in property initializers - Test at the unit boundary — mock only at system edges (network, filesystem)
xcodebuild Tooling
Prefer make targets over direct xcodebuild invocations. Projects expose:
make build # xcodebuild build
make test # xcodebuild test
make lint # SwiftLint
make format # SwiftFormat (fix)
make format-check # SwiftFormat (check only, for CI)
make check # build + lint + format-check + test
Running directly when needed:
xcodebuild build -scheme MyApp -destination 'platform=macOS'
xcodebuild test -scheme MyApp -destination 'platform=macOS'
Code Signing (macOS)
- Debug builds: automatic signing, any team
- Release/distribution builds: specific team ID, provisioning profile
- Notarization required for distribution outside the App Store
- Entitlements (
*.entitlements) must match capabilities declared in the target
Never hardcode signing identity strings — use CODE_SIGN_IDENTITY= with build setting variables.
04 同仓库更多 Skills
doctor
暂无简介
add-seat
Add a named seat to a Wheelhouse - a crew member, a standing role (such as a dispatcher) or a worker - as a ynh harness with its charter, standing orders and only the tools its job needs, named from the Wheelhouse's roster. Use when asked to add, create or set up a seat, role, worker or agent in a Wheelhouse (a release manager, a PR watcher, a dispatcher, a designer, more workers), or to give a role a name, or to start on a Wheelhouse's team (its starter team), one role at a time. Also use to trial, make official or drop a seat.
voice
How voices work - what a voice skill contains, how to write a new one, and how several voices compose into one reply. Use whenever drafting a reply in a named voice, or when asked to create or change a voice.
voice-warm
A friendly voice that acknowledges the person and their effort. Compose with direct for friendly but brief.
voice-formal
A careful, complete voice for people outside the team - customers, partners, senior stakeholders.
voice-direct
A plain, brief voice that leads with the answer. The default when no voice is named.