Skip to content
Back to skills

Swift Rules

ASecurity

Swift coding rules: style, patterns, security, testing. Triggers: .swift, Package.swift, .xcodeproj, SwiftUI, Combine, async/await, XCTest.

  • 177 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 27, 2026
developmentgoswiftsqlreactexpresstestingapidatabasesecurityperformance

Works with

  • cli
  • api

Security analysis

A100/100

Scanned May 27, 2026

npx -y skills add softspark/ai-toolkit --skill swift-rules --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Swift Rules?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Swift Rules
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/softspark-swift-rules/badge)](https://www.skillsdirectory.com/skills/softspark-swift-rules)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: swift-rules
description: "Swift coding rules: style, patterns, security, testing. Triggers: .swift, Package.swift, .xcodeproj, SwiftUI, Combine, async/await, XCTest."
effort: medium
user-invocable: false
allowed-tools: Read
---

# Swift Rules

These rules come from `app/rules/swift/` in ai-toolkit. They cover
the project's standards for coding style, frameworks, patterns,
security, and testing in Swift. Apply them when writing or
reviewing Swift code.

# Swift Coding Style

## Naming
- PascalCase: types, protocols, enums, struct, class.
- camelCase: functions, methods, properties, variables, enum cases.
- No prefixes: Swift has module namespacing (no `NS` or `UI` prefix for your types).
- Use descriptive names: `removeElement(at:)` not `remove(i:)`.
- Boolean properties read as assertions: `isEmpty`, `hasChildren`, `canSubmit`.

## Types
- Prefer `struct` over `class` by default (value semantics, no reference cycles).
- Use `class` only when reference semantics or inheritance is required.
- Use `enum` with associated values for modeling finite states.
- Use `protocol` for defining capabilities. Prefer protocol composition.
- Use `typealias` for complex generic signatures for readability.

## Optionals
- Use `guard let` for early exit on nil. Use `if let` for conditional binding.
- Never force-unwrap (`!`) unless failure is a programming error.
- Use `??` for default values: `let name = user?.name ?? "Unknown"`.
- Use optional chaining: `user?.address?.city`.
- Use `map` / `flatMap` on optionals for transformations.

## Properties
- Use `let` by default. Use `var` only when mutation is required.
- Use computed properties for derived values: `var fullName: String { ... }`.
- Use property observers (`willSet`, `didSet`) for side effects on change.
- Use `lazy var` for expensive initialization deferred until first access.
- Use `@Published` (Combine) for observable properties in classes.

## Functions
- Use argument labels for clarity: `func move(from source: Int, to destination: Int)`.
- Omit argument labels when the function name makes the role clear: `func contains(_ element: T)`.
- Use default parameter values instead of multiple overloads.
- Use `throws` / `async throws` for fallible operations.
- Use trailing closure syntax for the last closure parameter.

## Access Control
- Use `private` for implementation details. Use `fileprivate` sparingly.
- Use `internal` (default) for module-scoped access.
- Use `public` for framework API. Use `open` only when subclassing is intended.
- Prefer `private(set)` for read-only external access with internal mutation.

## Formatting
- Use SwiftLint for automated style enforcement.
- Use SwiftFormat for automated code formatting.
- Commit `.swiftlint.yml` and `.swiftformat` to the repository.
- Max line length: 120 characters (SwiftLint default).
- Use trailing commas in multi-line arrays and dictionaries.

# Swift Frameworks

## SwiftUI
- Use `VStack`, `HStack`, `ZStack` for layout composition.
- Use `List` with `ForEach` for dynamic content. Use `LazyVStack` for large lists.
- Use `NavigationStack` (iOS 16+) with `navigationDestination(for:)` for type-safe navigation.
- Use `.task { }` modifier for async data loading tied to view lifecycle.
- Use `@ViewBuilder` for conditional view composition in custom containers.
- Use `PreviewProvider` or `#Preview` macro for rapid UI iteration.

## UIKit (Legacy / Hybrid)
- Use `UIHostingController` to embed SwiftUI views in UIKit.
- Use `UIViewRepresentable` to wrap UIKit views in SwiftUI.
- Use Auto Layout with constraints or `UIStackView` for layout.
- Use `UICollectionViewCompositionalLayout` for complex collection layouts.
- Use `Coordinator` pattern for delegate-based UIKit interop in SwiftUI.

## Combine
- Use `Publisher` / `Subscriber` for reactive data streams.
- Use `sink` for subscribing. Store cancellables in `Set<AnyCancellable>`.
- Use `map`, `filter`, `flatMap`, `combineLatest` for stream transformation.
- Use `@Published` on class properties for automatic publisher generation.
- Prefer `AsyncSequence` (async/await) over Combine for new code.

## Swift Data
- Use `@Model` macro for persistent model definitions.
- Use `@Query` in SwiftUI views for automatic fetching and observation.
- Use `ModelContext` for CRUD operations: `context.insert(item)`, `context.delete(item)`.
- Use `#Predicate` macro for type-safe query filtering.
- Use `ModelConfiguration` for custom store locations and migration options.

## Core Data (Legacy)
- Use `NSPersistentContainer` for stack setup.
- Use `NSFetchRequest` with `NSPredicate` for querying.
- Use `performBackgroundTask` for background context operations.
- Use lightweight migrations for schema changes when possible.
- Prefer SwiftData for new projects (iOS 17+).

## Vapor (Server-Side)
- Use `routes.get("users")` for route definitions.
- Use `Content` protocol for request/response body codable conformance.
- Use Fluent ORM with migrations for database access.
- Use middleware for authentication, CORS, and error handling.
- Use `async`/`await` natively (Vapor 4+ is fully async).

## Networking
- Use `URLSession` with `async/await` for HTTP requests.
- Use `Codable` with `JSONDecoder` for response parsing.
- Use `URLCache` and `ETag` for response caching.
- Set `timeoutIntervalForRequest` on `URLSessionConfiguration`.
- Use `TaskLocal` for request-scoped values (tracing, auth context).

## Package Management
- Use Swift Package Manager (SPM) for dependency management.
- Define dependencies in `Package.swift` with exact version or version ranges.
- Use `Package.resolved` committed to the repository for reproducible builds.
- Prefer SPM over CocoaPods/Carthage for new projects.

# Swift Patterns

## Error Handling
- Use `enum AppError: Error` for typed, exhaustive error handling.
- Use `throws` functions with `do-catch` for recoverable errors.
- Use `Result<Success, Failure>` for asynchronous error propagation.
- Use `try?` for optional conversion. Use `try!` only in tests or guaranteed paths.
- Add `LocalizedError` conformance for user-facing error messages.

## Protocol-Oriented Design
- Define capabilities as protocols: `protocol Fetchable { func fetch() async throws -> Data }`.
- Use protocol extensions for default implementations.
- Use protocol composition: `func process(_ item: Sendable & Codable)`.
- Use associated types for generic protocols: `associatedtype Output`.
- Use `some Protocol` (opaque types) for return types hiding concrete implementations.

## Async/Await
- Use `async` functions for all asynchronous operations.
- Use `async let` for concurrent, independent operations.
- Use `TaskGroup` for dynamic parallelism with collected results.
- Use `Task { }` to bridge sync to async. Avoid `.task { }` in views for complex logic.
- Use `withThrowingTaskGroup` for concurrent operations that can fail.

## Actors
- Use `actor` for thread-safe mutable state (replaces manual locks).
- Use `@MainActor` for UI-related state and methods.
- Use `nonisolated` for actor methods that do not access mutable state.
- Use `GlobalActor` for custom isolation domains.
- Minimize `await` calls on actors to reduce suspension points.

## SwiftUI Patterns
- Use `@State` for view-local mutable state.
- Use `@Binding` for child-to-parent state communication.
- Use `@Observable` (Observation framework) for model objects (preferred over `@ObservedObject`).
- Use `@Environment` for dependency injection: `@Environment(\.modelContext)`.
- Use `ViewModifier` for reusable view transformations.
- Extract subviews into separate structs for readability and performance.

## Codable
- Use `Codable` for JSON serialization/deserialization.
- Use `CodingKeys` enum for custom key mapping.
- Use `JSONDecoder` with `.convertFromSnakeCase` for API compatibility.
- Use `@propertyWrapper` for custom decoding strategies (e.g., date formats).
- Use `nestedContainer` for flattening nested JSON structures.

## Dependency Injection
- Use initializer injection for required dependencies.
- Use `@Environment` in SwiftUI for framework-provided values.
- Use `swift-dependencies` library for testable, controlled dependency management.
- Use `@Dependency(\.apiClient) var apiClient` for automatic resolution.

## Anti-Patterns
- Force-unwrapping optionals: use `guard let` or `??`.
- Massive view controllers/views: split into subviews and view models.
- Reference cycles: use `[weak self]` in closures capturing `self`.
- Blocking the main thread: use `Task` or `DispatchQueue.global()`.
- Stringly-typed APIs: use enums, protocols, and strong types.

# Swift Security

## Keychain
- Use Keychain Services for storing passwords, tokens, and cryptographic keys.
- Use `kSecAttrAccessibleWhenUnlockedThisDeviceOnly` for sensitive items.
- Use `KeychainAccess` or similar wrapper libraries for cleaner API.
- Never store secrets in `UserDefaults` (unencrypted plist on disk).
- Delete keychain items on user logout.

## App Transport Security (ATS)
- Use HTTPS for all network connections. ATS enforces this by default.
- Never add blanket `NSAllowsArbitraryLoads` exception.
- Use per-domain exceptions only when connecting to legacy servers.
- Implement certificate pinning for high-security connections.
- Validate server certificates in `URLSessionDelegate` for custom pinning.

## Input Validation
- Validate all user input before processing or displaying.
- Use `NSRegularExpression` or Swift Regex for pattern validation.
- Sanitize strings before using in URL construction, SQL, or HTML.
- Validate deep link URL parameters before navigation.
- Limit input lengths in `UITextField` / `TextField` to prevent abuse.

## Data Protection
- Use `Data Protection` API: set `FileProtectionType.complete` on sensitive files.
- Use `CryptoKit` for hashing (`SHA256`), encryption (`AES.GCM`), and signing.
- Use `SecureEnclave` for hardware-backed key storage on supported devices.
- Zero sensitive data in memory after use: `withUnsafeMutableBytes { $0.initializeMemory(as: UInt8.self, repeating: 0) }`.
- Use `@Sendable` closures to prevent data races in concurrent access.

## Authentication
- Use `AuthenticationServices` for Sign in with Apple and passkeys.
- Use `LocalAuthentication` (Face ID / Touch ID) for biometric auth.
- Store authentication tokens in Keychain, not in memory or UserDefaults.
- Use short-lived access tokens with refresh token rotation.
- Implement session timeout for inactive users.

## Network Security
- Use `URLSession` with certificate pinning for sensitive API calls.
- Validate response `Content-Type` headers before parsing.
- Use `Codable` for structured deserialization (prevents injection).
- Set request timeouts to prevent hanging connections.
- Do not log request/response bodies containing sensitive data.

## Code Security
- Use `[weak self]` in closures to prevent retain cycles and memory leaks.
- Use `@Sendable` and actor isolation for thread-safe concurrent code.
- Avoid `UnsafePointer` / `UnsafeMutablePointer` unless absolutely necessary.
- Use `#if DEBUG` guards for debug-only code. Never ship debug features.
- Enable Xcode hardened runtime for macOS apps.

## Dependency Security
- Audit SPM dependencies before adding. Check maintainer reputation.
- Pin dependency versions in `Package.resolved`.
- Review `Package.swift` of dependencies for unusual build plugins.
- Prefer dependencies with active security response and disclosure processes.
- Minimize third-party dependencies for security-critical modules.

# Swift Testing

## Framework
- Use Swift Testing (`import Testing`) for new projects (Swift 5.10+).
- Use XCTest for existing projects and UIKit-based UI tests.
- Use swift-snapshot-testing for visual regression testing.
- Use swift-dependencies for controlled dependency injection in tests.

## File Naming
- Test files: `FooTests.swift` in `Tests/` target.
- Mirror source module structure in test target.
- Use `@Test` attribute (Swift Testing) or `test` prefix (XCTest) for test methods.
- Use `@Suite` (Swift Testing) for test grouping.

## Structure (Swift Testing)
- Use `@Test("description")` for individual test cases.
- Use `@Test(arguments: [...])` for parameterized tests.
- Use `#expect(condition)` for assertions. Use `#require(condition)` for preconditions.
- Use `#expect(throws: FooError.self) { try riskyOperation() }` for error testing.
- Use `@Suite` structs for grouping. Properties serve as shared setup.

## Structure (XCTest)
- Use `setUp()` / `tearDown()` for per-test initialization and cleanup.
- Use `setUpWithError()` for throwing setup code.
- Use `XCTAssertEqual`, `XCTAssertTrue`, `XCTAssertNil` for assertions.
- Use `XCTAssertThrowsError` for exception testing.
- Use `expectation(description:)` + `wait(for:timeout:)` for async assertions.

## Async Testing
- Use `async` test functions: `@Test func fetchUser() async throws { ... }`.
- Use `confirmation()` (Swift Testing) for event-based async assertions.
- XCTest: use `XCTestExpectation` with `fulfillment()` for callback-based async.
- Test `AsyncSequence` with `for await` loops and assertion on collected values.

## Mocking
- Use protocol-based dependency injection for testability.
- Create manual mock implementations conforming to protocols.
- Use `swift-dependencies` for environment-controlled dependency overrides.
- Use `@Dependency` property wrapper for automatic mock injection in tests.
- Avoid mocking frameworks when protocol mocks are straightforward.

## UI Testing (XCTest)
- Use `XCUIApplication` for UI automation tests.
- Use accessibility identifiers for reliable element lookup.
- Use `app.buttons["Submit"].tap()` for interaction simulation.
- Use `waitForExistence(timeout:)` for async UI element appearance.
- Keep UI tests focused on critical user flows only (slow to run).

## Best Practices
- Test behavior through public API. Avoid `@testable import` when possible.
- Use `@testable import Module` only when testing internal members is necessary.
- Use `withDependencies { }` for scoped dependency overrides in tests.
- Test on multiple platforms (iOS, macOS) when shipping cross-platform.
- Run tests with `swift test` or `xcodebuild test` in CI.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.