mcpField
S
swift

swift

github.com/dralgorhythmDevelopment12956 installsUpdated 15w ago
Repository

About swift

A development skill guide for Swift and iOS projects, covering setup, language patterns, SwiftUI, concurrency, testing, and code tools. It is intended for developers building or maintaining Swift applications.

Key features

  1. 01Swift Package Manager and Xcode setup
  2. 02Optional, Result, and protocol patterns
  3. 03async/await, structured concurrency, and actors
  4. 04SwiftUI state and dependency injection
  5. 05Swift Testing and XCTest
  6. 06SwiftLint and SwiftFormat configuration

Use cases

  1. 01Initialize a Swift executable package
  2. 02Write asynchronous network requests and concurrent tasks
  3. 03Build stateful SwiftUI interfaces
  4. 04Test services and check code formatting

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/dralgorhythm/claude-agentic-framework --skill swift

After installing, type/swiftin Claude Code to confirm it loaded.

Details

From the project README

Swift / iOS Development

Project Setup

Swift Package Manager
# Initialize new package
swift package init --type executable

# Add dependencies to Package.swift
# swift package update
Package.swift
// swift-tools-version: 5.10
import PackageDescription

let package = Package(
    name: "MyApp",
    platforms: [.iOS(.v17), .macOS(.v14)],
    products: [
        .library(name: "MyApp", targets: ["MyApp"]),
    ],
    dependencies: [
        // Add dependencies here
    ],
    targets: [
        .target(name: "MyApp", dependencies: []),
        .testTarget(name: "MyAppTests", dependencies: ["MyApp"]),
    ]
)
Xcode Project
# Create new Xcode project via Xcode or:
# Use SwiftUI App template for new projects
# Target iOS 17+ for latest APIs

Type Patterns

Optionals
// Safe unwrapping
if let user = optionalUser {
    print(user.name)
}

// Guard for early exit
guard let user = optionalUser else {
    return
}

// Optional chaining
let name = user?.profile?.displayName ?? "Anonymous"

// Nil coalescing
let displayName = user?.name ?? "Guest"
Result Type
enum NetworkError: Error {
    case invalidURL
    case noData
    case decodingFailed
}

func fetchUser(id: String) async -> Result<User, NetworkError> {
    guard let url = URL(string: "https://api.example.com/users/\(id)") else {
        return .failure(.invalidURL)
    }

    do {
        let (data, _) = try await URLSession.shared.data(from: url)
        let user = try JSONDecoder().decode(User.self, from: data)
        return .success(user)
    } catch {
        return .failure(.decodingFailed)
    }
}

// Usage
switch await fetchUser(id: "123") {
case .success(let user):
    print("Got user: \(user.name)")
case .failure(let error):
    print("Error: \(error)")
}
Protocols & Extensions
protocol Identifiable {
    var id: UUID { get }
}

protocol Displayable {
    var displayName: String { get }
}

extension User: Identifiable, Displayable {
    var displayName: String {
        "\(firstName) \(lastName)"
    }
}

Error Handling

// Throwing functions
func loadConfig() throws -> Config {
    guard let data = FileManager.default.contents(atPath: configPath) else {
        throw ConfigError.fileNotFound
    }
    return try JSONDecoder().decode(Config.self, from: data)
}

// Do-catch
do {
    let config = try loadConfig()
    print(config)
} catch ConfigError.fileNotFound {
    print("Config file missing")
} catch {
    print("Unknown error: \(error)")
}

// Try? for optional result
let config = try? loadConfig()

// Try! only when failure is impossible
let bundledConfig = try! loadBundledConfig()

Async/Await Patterns

Basic Async
func fetchUsers() async throws -> [User] {
    let (data, _) = try await URLSession.shared.data(from: usersURL)
    return try JSONDecoder().decode([User].self, from: data)
}

// Calling async functions
Task {
    do {
        let users = try await fetchUsers()
        await MainActor.run {
            self.users = users
        }
    } catch {
        print("Failed: \(error)")
    }
}
Structured Concurrency
// Parallel execution
async let users = fetchUsers()
async let posts = fetchPosts()
let (userList, postList) = try await (users, posts)

// Task groups
func fetchAllUserData(ids: [String]) async throws -> [UserData] {
    try await withThrowingTaskGroup(of: UserData.self) { group in
        for id in ids {
            group.addTask {
                try await fetchUserData(id: id)
            }
        }
        return try await group.reduce(into: []) { $0.append($1) }
    }
}
Actors
actor UserCache {
    private var cache: [String: User] = [:]

    func get(_ id: String) -> User? {
        cache[id]
    }

    func set(_ user: User) {
        cache[user.id] = user
    }
}

// Usage
let cache = UserCache()
await cache.set(user)
let cached = await cache.get("123")

SwiftUI Patterns

View with State
struct ContentView: View {
    @State private var count = 0
    @State private var username = ""

    var body: some View {
        VStack(spacing: 16) {
            Text("Count: \(count)")
                .font(.title)

            Button("Increment") {
                count += 1
            }

            TextField("Username", text: $username)
                .textFieldStyle(.roundedBorder)
        }
        .padding()
    }
}
Observable ViewModel
@Observable
class UserViewModel {
    var users: [User] = []
    var isLoading = false
    var error: Error?

    func loadUsers() async {
        isLoading = true
        defer { isLoading = false }

        do {
            users = try await userService.fetchAll()
        } catch {
            self.error = error
        }
    }
}

struct UserListView: View {
    @State private var viewModel = UserViewModel()

    var body: some View {
        List(viewModel.users) { user in
            UserRow(user: user)
        }
        .task {
            await viewModel.loadUsers()
        }
        .overlay {
            if viewModel.isLoading {
                ProgressView()
            }
        }
    }
}
Environment & Dependency Injection
// Define environment key
struct UserServiceKey: EnvironmentKey {
    static let defaultValue: UserService = .live
}

extension EnvironmentValues {
    var userService: UserService {
        get { self[UserServiceKey.self] }
        set { self[UserServiceKey.self] = newValue }
    }
}

// Use in view
struct ProfileView: View {
    @Environment(\.userService) private var userService

    var body: some View {
        // Use userService
    }
}

Testing

Swift Testing (Swift 6+)
import Testing

@Suite("UserService Tests")
struct UserServiceTests {
    let service = UserService()

    @Test("creates user with valid email")
    func createUser() async throws {
        let user = try await service.create(email: "[email protected]")
        #expect(user.email == "[email protected]")
    }

    @Test("throws on invalid email")
    func invalidEmail() async {
        await #expect(throws: ValidationError.self) {
            try await service.create(email: "invalid")
        }
    }

    @Test("fetches user by ID", arguments: ["user1", "user2", "user3"])
    func fetchUser(id: String) async throws {
        let user = try await service.fetch(id: id)
        #expect(user.id == id)
    }
}
XCTest (Legacy)
import XCTest
@testable import MyApp

final class UserServiceTests: XCTestCase {
    var service: UserService!

    override func setUp() {
        super.setUp()
        service = UserService()
    }

    func testCreateUser() async throws {
        let user = try await service.create(email: "[email protected]")
        XCTAssertEqual(user.email, "[email protected]")
    }

    func testInvalidEmailThrows() async {
        do {
            _ = try await service.create(email: "invalid")
            XCTFail("Expected error")
        } catch {
            XCTAssertTrue(error is ValidationError)
        }
    }
}

Tooling

# SwiftLint (linting)
brew install swiftlint
swiftlint lint
swiftlint lint --fix

# SwiftFormat (formatting)
brew install swiftformat
swiftformat .
swiftformat . --lint

# Run tests
swift test
xcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15'

# Build
swift build
xcodebuild build -scheme MyApp

# fastlane (CI/CD)
brew install fastlane
fastlane init
fastlane ios test
fastlane ios beta  # Deploy to TestFlight
.swiftlint.yml
disabled_rules:
  - trailing_whitespace
  - line_length

opt_in_rules:
  - empty_count
  - empty_string

excluded:
  - Pods
  - .build
.swiftformat
--indent 4
--allman false
--wraparguments before-first
--wrapparameters before-first
--self remove
--importgrouping alphabetized

Comments

Markdown supported