Skip to content
Back to skills

121 Swift 0bb827a0

ASecurity

```swift import SwiftUI

  • 9 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 11, 2026
designswiftspringapiperformance

Works with

  • api

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 121-swift_0bb827a0 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 121 Swift 0bb827a0?

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

Security grade badge for 121 Swift 0bb827a0
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-121-swift-0bb827a0/badge)](https://www.skillsdirectory.com/skills/tools-only-121-swift-0bb827a0)

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

SKILL.md
# SwiftUI Patterns

## State Management

```swift
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

```swift
// 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

```swift
// 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

```swift
// 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

```swift
// 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

```swift
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+)

```swift
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

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.