All skills
jeffallan avatar

/swift-expert

@efebc44
by jeffallanjeffallan/claude-skills12k stars
1,124

Builds iOS/macOS/watchOS/tvOS applications, implements SwiftUI views and state management, designs protocol-oriented architectures, handles async/await concurrency, implements actors for thread safety, and debugs Swift-specific issues. Use when building iOS/macOS applications with Swift 5.9+, SwiftUI, or async/await concurrency. Invoke for protocol-oriented programming, SwiftUI state management, actors, server-side Swift, UIKit integration, Combine, or Vapor.

Use this Skill: https://skilld.dev/gh/jeffallan/claude-skills/swift-expert

This session only. Nothing lands on disk.

referencesswiftui-patterns.md

≈1.7k tokens on demand. Your agent reads this file only when SKILL.md points to it.

SwiftUI Patterns

State Management

import SwiftUI

// @State for local view state
struct CounterView: View {
    @State private var count = 0

    var body: some View {
        VStack {
            Text("Count: \(count)")
            Button("Increment") { count += 1 }
        }
    }
}

// @Binding for two-way data flow
struct ToggleView: View {
    @Binding var isOn: Bool

    var body: some View {
        Toggle("Enable Feature", isOn: $isOn)
    }
}

// @StateObject for observable objects (view owns it)
class ViewModel: ObservableObject {
    @Published var items: [String] = []
    @Published var isLoading = false
}

struct ContentView: View {
    @StateObject private var viewModel = ViewModel()

    var body: some View {
        List(viewModel.items, id: \.self) { item in
            Text(item)
        }
    }
}

// @ObservedObject for passed-in observable objects
struct DetailView: View {
    @ObservedObject var viewModel: ViewModel
}

// @EnvironmentObject for dependency injection
struct AppView: View {
    @EnvironmentObject var appState: AppState
}

Modern View Composition

// View builder for custom containers
struct ConditionalView<Content: View>: View {
    let condition: Bool
    @ViewBuilder let content: () -> Content

    var body: some View {
        if condition {
            content()
        } else {
            EmptyView()
        }
    }
}

// Custom ViewModifier
struct CardModifier: ViewModifier {
    func body(content: Content) -> some View {
        content
            .padding()
            .background(Color.white)
            .cornerRadius(12)
            .shadow(radius: 4)
    }
}

extension View {
    func cardStyle() -> some View {
        modifier(CardModifier())
    }
}

// Usage
Text("Hello")
    .cardStyle()

Environment Values

// Custom environment key
private struct ThemeKey: EnvironmentKey {
    static let defaultValue: Theme = .light
}

extension EnvironmentValues {
    var theme: Theme {
        get { self[ThemeKey.self] }
        set { self[ThemeKey.self] = newValue }
    }
}

extension View {
    func theme(_ theme: Theme) -> some View {
        environment(\.theme, theme)
    }
}

// Usage
struct ThemedView: View {
    @Environment(\.theme) var theme

    var body: some View {
        Text("Themed")
            .foregroundColor(theme.textColor)
    }
}

Preference Keys

// Collecting data from child views
struct SizePreferenceKey: PreferenceKey {
    static var defaultValue: CGSize = .zero

    static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
        value = nextValue()
    }
}

struct MeasurableView: View {
    @State private var size: CGSize = .zero

    var body: some View {
        Text("Measure me")
            .background(
                GeometryReader { geometry in
                    Color.clear
                        .preference(key: SizePreferenceKey.self, value: geometry.size)
                }
            )
            .onPreferenceChange(SizePreferenceKey.self) { newSize in
                size = newSize
            }
    }
}

Animations

// Implicit animations
struct AnimatedView: View {
    @State private var scale: CGFloat = 1.0

    var body: some View {
        Circle()
            .scaleEffect(scale)
            .animation(.spring(response: 0.5, dampingFraction: 0.6), value: scale)
            .onTapGesture {
                scale = scale == 1.0 ? 1.5 : 1.0
            }
    }
}

// Explicit animations
struct ExplicitAnimationView: View {
    @State private var offset: CGFloat = 0

    var body: some View {
        Text("Slide")
            .offset(x: offset)
            .onTapGesture {
                withAnimation(.easeInOut(duration: 0.3)) {
                    offset = offset == 0 ? 100 : 0
                }
            }
    }
}

// Custom transitions
extension AnyTransition {
    static var slideAndFade: AnyTransition {
        AnyTransition.slide.combined(with: .opacity)
    }
}

Async/Await Integration

struct AsyncDataView: View {
    @State private var data: [Item] = []
    @State private var isLoading = false

    var body: some View {
        List(data) { item in
            Text(item.title)
        }
        .task {
            await loadData()
        }
        .refreshable {
            await loadData()
        }
    }

    private func loadData() async {
        isLoading = true
        defer { isLoading = false }

        do {
            data = try await API.fetchItems()
        } catch {
            print("Error: \(error)")
        }
    }
}

Custom Layouts (iOS 16+)

struct WaterfallLayout: Layout {
    var columns: Int = 2
    var spacing: CGFloat = 8

    func sizeThatFits(
        proposal: ProposedViewSize,
        subviews: Subviews,
        cache: inout ()
    ) -> CGSize {
        // Calculate total size needed
        let columnWidth = (proposal.width! - spacing * CGFloat(columns - 1)) / CGFloat(columns)
        var columnHeights = Array(repeating: CGFloat(0), count: columns)

        for subview in subviews {
            let column = columnHeights.enumerated().min(by: { $0.element < $1.element })!.offset
            let size = subview.sizeThatFits(.init(width: columnWidth, height: nil))
            columnHeights[column] += size.height + spacing
        }

        return CGSize(
            width: proposal.width!,
            height: columnHeights.max()! - spacing
        )
    }

    func placeSubviews(
        in bounds: CGRect,
        proposal: ProposedViewSize,
        subviews: Subviews,
        cache: inout ()
    ) {
        let columnWidth = (bounds.width - spacing * CGFloat(columns - 1)) / CGFloat(columns)
        var columnHeights = Array(repeating: CGFloat(0), count: columns)

        for subview in subviews {
            let column = columnHeights.enumerated().min(by: { $0.element < $1.element })!.offset
            let x = bounds.minX + CGFloat(column) * (columnWidth + spacing)
            let y = bounds.minY + columnHeights[column]

            subview.place(
                at: CGPoint(x: x, y: y),
                proposal: .init(width: columnWidth, height: nil)
            )

            columnHeights[column] += subview.dimensions(in: .init(width: columnWidth, height: nil)).height + spacing
        }
    }
}

Performance Tips

  • Use @State for simple value types
  • Use @StateObject for reference types you create
  • Use @ObservedObject for reference types passed in
  • Prefer @Environment over prop drilling
  • Use equatable() modifier for expensive views
  • Leverage id() modifier to control view identity
  • Use task(id:) to cancel and restart async work
  • Avoid computing expensive values in body - use @State or computed properties

Source: SKILL.md on GitHub

1 alert16d5 checks · Risk CRITICAL
  • Gen Agent Trust Hub16d

    The skill provides comprehensive instructions and reference material for professional Swift development on Apple platforms. No malicious patterns, obfuscation, or security risks were identified within the skill instructions, reference files, or code examples.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    6 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at efebc44. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 5 months ago
Other metadata
metadata
{
  "author": "https://github.com/Jeffallan",
  "version": "1.1.0",
  "domain": "language",
  "triggers": "Swift, SwiftUI, iOS development, macOS development, async/await Swift, Combine, UIKit, Vapor",
  "role": "specialist",
  "scope": "implementation",
  "output-format": "code",
  "related-skills": null
}

README badge

README badge for jeffallan/claude-skills/swift-expert