L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Design et création · SKILL.md

swift

swift

Swift language fundamentals (5.10+ / 6.x). Covers optionals, value vs reference semantics, protocols & generics, Swift Concurrency (async/await, actors, Sendable, structured tasks), Result Builders, and Apple platform interop. USE WHEN: user mentions "Swift", "SwiftUI", "async/await Swift", "actor", "Sendable", "Codable", "Combine", "Result Builder", "Appl…

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: swift description: | Swift language fundamentals (5.10+ / 6.x). Covers optionals, value vs reference semantics, protocols & generics, Swift Concurrency (async/await, actors, Sendable, structured tasks), Result Builders, and Apple platform interop.

USE WHEN: user mentions "Swift", "SwiftUI", "async/await Swift", "actor", "Sendable", "Codable", "Combine", "Result Builder", "Apple Keychain", "Secure Enclave", "iOS native"

DO NOT USE FOR: reviewing existing Swift code - use review/swift, which covers retain cycles and the concurrency checking that is a per-target setting DO NOT USE FOR: SwiftUI screen layouts in depth - use SwiftUI-specific skill if exists DO NOT USE FOR: Compose iOS via Skia - use frontend-frameworks/compose-multiplatform DO NOT USE FOR: Kotlin/Native ↔ Swift bridging - use languages/uniffi allowed-tools: Read, Grep, Glob, Write, Edit

Swift Core Knowledge

References: concurrency.md for async/await, actors, Sendable, structured tasks. interop.md for ObjC, C, and Rust (cinterop) bridging, Keychain, Secure Enclave.

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: swift.

Optionals

var name: String = "Alice"           // Non-optional
var maybe: String? = nil             // Optional (sugar for Optional<String>)

// Force-unwrap (avoid)
let n = maybe!                       // Crash if nil

// Optional binding
if let n = maybe {
    print("got \(n)")
}

// Guard (early exit)
func greet(_ name: String?) {
    guard let name else { return }
    print("Hello, \(name)")
}

// Nil coalescing
let display = maybe ?? "Anonymous"

// Optional chaining
let len = maybe?.count               // Int?

Use guard let name else { ... } (Swift 5.7+) — implicit shadow shorter than guard let name = name else.

Value vs Reference Types

KindSemanticsAllocationUse for
structValue (copied on assign/pass)Stack (usually)Models, lightweight data, thread-safe by default
enumValueStackDiscriminated unions, sealed states
classReference (shared identity)HeapIdentity, inheritance, ObjC interop
actorReference + isolatedHeapMutable state across concurrency
struct Point { var x: Double; var y: Double }
var a = Point(x: 1, y: 2)
var b = a            // copy
b.x = 10
// a.x still 1, b.x is 10

class Node { var value: Int = 0 }
let n1 = Node()
let n2 = n1          // same instance
n2.value = 42        // n1.value also 42

Default to struct. Use class only for identity, mutable shared state, or ObjC inheritance.

Enums with Associated Values

enum NetworkResult<Success> {
    case success(Success)
    case failure(NetworkError)
    case loading
}

enum NetworkError: Error {
    case unauthorized
    case server(code: Int, body: String)
    case timeout(after: TimeInterval)
}

func handle<T>(_ result: NetworkResult<T>) -> String {
    switch result {
    case .success(let value):
        return "ok: \(value)"
    case .failure(.unauthorized):
        return "login"
    case .failure(.server(let code, _)):
        return "server \(code)"
    case .failure(.timeout(let t)):
        return "timeout \(t)"
    case .loading:
        return "loading"
    }
}

switch is exhaustive — no default needed when all cases covered. Compiler enforces.

Protocols & Generics

protocol Identifiable {
    associatedtype ID: Hashable
    var id: ID { get }
}

struct User: Identifiable {
    let id: Int
    let name: String
}

// Protocol-oriented design
protocol Drawable { func draw() }

extension Drawable where Self: Identifiable, Self.ID == Int {
    func describe() -> String { "drawable id=\(id)" }
}

// Generic constraints
func first<C: Collection>(_ c: C) -> C.Element? where C.Element: Equatable {
    c.first
}

// Existential ('any') vs opaque ('some')
func makeShape() -> some Drawable { Circle() }     // concrete type, hidden
func loadShapes() -> [any Drawable] { [Circle(), Square()] }  // heterogeneous

Prefer some over any — opaque types preserve type identity for the compiler (no boxing). Use any only when truly heterogeneous.

Codable

struct User: Codable {
    let id: Int
    let name: String
    let email: String?
    let createdAt: Date

    enum CodingKeys: String, CodingKey {
        case id, name, email
        case createdAt = "created_at"
    }
}

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
decoder.keyDecodingStrategy = .convertFromSnakeCase  // alternative to CodingKeys

let user = try decoder.decode(User.self, from: jsonData)

let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
let data = try encoder.encode(user)

For BHODL-style FFI, prefer Codable for IPC payloads and JSONEncoder/Decoder over manual parsing.

Error Handling

enum WalletError: Error {
    case insufficientFunds(Amount)
    case invalidAddress(String)
}

func send(amount: Amount, to address: String) throws -> Transaction {
    guard isValid(address) else { throw WalletError.invalidAddress(address) }
    guard hasFunds(amount) else { throw WalletError.insufficientFunds(amount) }
    return buildTx(amount, address)
}

// Call site
do {
    let tx = try send(amount: 1000, to: "bc1q...")
    print(tx)
} catch WalletError.insufficientFunds(let need) {
    print("need \(need)")
} catch {
    print("other error: \(error)")
}

// try? returns optional, try! force-unwraps (avoid)
let tx = try? send(amount: 1000, to: address)

Result Builders (DSLs)

Power SwiftUI's body and many Apple DSLs.

@resultBuilder
struct StringBuilder {
    static func buildBlock(_ components: String...) -> String {
        components.joined(separator: "\n")
    }
    static func buildEither(first: String) -> String { first }
    static func buildEither(second: String) -> String { second }
}

@StringBuilder
func greeting(name: String, formal: Bool) -> String {
    "Hello"
    if formal { "Mr/Ms \(name)" } else { name }
    "Welcome"
}

Property Wrappers

@propertyWrapper
struct Clamped<Value: Comparable> {
    var value: Value
    let range: ClosedRange<Value>

    init(wrappedValue: Value, _ range: ClosedRange<Value>) {
        self.range = range
        self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
    }

    var wrappedValue: Value {
        get { value }
        set { value = min(max(newValue, range.lowerBound), range.upperBound) }
    }
}

struct Volume {
    @Clamped(0...100) var level: Int = 50
}

Common in SwiftUI (@State, @Binding, @StateObject, @Environment, @AppStorage).

Memory Management

ARC (Automatic Reference Counting). Watch for retain cycles.

class Node {
    var children: [Node] = []
    weak var parent: Node?           // weak breaks cycle
}

class ViewModel {
    private var task: Task<Void, Never>?

    func start() {
        task = Task { [weak self] in
            guard let self else { return }
            await self.load()
        }
    }
}

weak → optional, becomes nil when target deallocs. unowned → non-optional, crash on access if dealloc'd. Prefer weak unless lifetime guaranteed.

Concurrency — Essentials

func fetchUser(id: Int) async throws -> User {
    let (data, _) = try await URLSession.shared.data(from: url(id))
    return try JSONDecoder().decode(User.self, from: data)
}

// Parallel
async let user = fetchUser(id: 1)
async let posts = fetchPosts(userId: 1)
let result = try await (user, posts)

// Sequential
let user = try await fetchUser(id: 1)
let posts = try await fetchPosts(userId: user.id)

See concurrency.md for actors, Sendable, TaskGroup, AsyncStream, MainActor.

Anti-Patterns

Anti-patternWhy it's badCorrect approach
Force-unwrap ! everywhereCrash on nilguard let, if let, ??
class for value-like typesSurprising aliasingUse struct
Combine for new code (post-Swift Concurrency)Apple steering toward async/awaitPrefer AsyncSequence/AsyncStream
DispatchQueue.main.async from async codeUse @MainActorMainActor.run { ... } or annotate function
weak var everywhereHides ownership intentOnly break actual cycles
try! outside testsCrash on errortry? or proper do/catch
String-based KVO/selectorsNo type safetyUse KeyPath, Combine, async sequences
print for production loggingNo filter, no privacyUse os.Logger (import os)

Build & Tooling

// Package.swift (Swift Package Manager)
// swift-tools-version:6.0
import PackageDescription

let package = Package(
    name: "MyLib",
    platforms: [.iOS(.v17), .macOS(.v14)],
    products: [
        .library(name: "MyLib", targets: ["MyLib"]),
    ],
    dependencies: [
        .package(url: "https://github.com/apple/swift-algorithms.git", from: "1.2.0"),
    ],
    targets: [
        .target(name: "MyLib", dependencies: [
            .product(name: "Algorithms", package: "swift-algorithms"),
        ]),
        .testTarget(name: "MyLibTests", dependencies: ["MyLib"]),
    ]
)
swift build                        # Build
swift test                         # Run XCTest
swift run                          # Run executable target
swift package update               # Update deps
xcodebuild -scheme MyApp test      # Xcode CI build

Testing

// XCTest (legacy but widely used)
import XCTest
@testable import MyLib

final class UserTests: XCTestCase {
    func testValidEmail() {
        let u = User(id: 1, name: "x", email: "x@y.z")
        XCTAssertTrue(u.email.contains("@"))
    }

    func testAsync() async throws {
        let user = try await fetchUser(id: 1)
        XCTAssertEqual(user.id, 1)
    }
}

// Swift Testing (Swift 6+ — recommended for new code)
import Testing

@Suite struct UserTests {
    @Test func validEmail() {
        let u = User(id: 1, name: "x", email: "x@y.z")
        #expect(u.email.contains("@"))
    }

    @Test(arguments: [1, 2, 3])
    func userExists(id: Int) async throws {
        let user = try await fetchUser(id: id)
        #expect(user.id == id)
    }
}

When NOT to Use This Skill

ScenarioUse Instead
KMP from Rust → Swift bindingslanguages/uniffi
Compose Multiplatform iOS UIfrontend-frameworks/compose-multiplatform
iOS Keychain/Secure Enclave deep diveinterop.md
SwiftUI screen-by-screen architectureSwiftUI-specific skill (TBD)
ObjC migrationinterop.md
Skills enregistrées