Skip to content

Swift Expert Complete Guide for Beginners - Usage Examples & Best Practices

Purpose

This post demonstrates how to use Swift Expert skill in Claude Code for effective iOS and macOS development.

Environment

  • Claude Code with claude-skills plugin
  • Swift 5.9+
  • Xcode 15+
  • macOS 14+ (for iOS development)

What is Swift Expert?

Swift Expert is a specialized skill in the claude-skills ecosystem that provides idiomatic Swift development patterns, best practices, and conventions. When I need to write robust Swift code, this skill helps me follow Apple’s guidelines and community standards.

There are several key benefits:

  • Idiomatic patterns: Swift-specific conventions like optionals, closures, and protocol-oriented design
  • Best practices: Memory management, error handling, and Swift-style architecture
  • Type safety: Leverages Swift’s strong type system effectively
  • Performance: Optimized Swift code that avoids common pitfalls

Installation and Setup

First, I need to install claude-skills plugin in my Claude Code environment:

Install claude-skills
cd ~/.claude
git clone https://github.com/jeffallan/claude-skills.git

Then verify Swift Expert is available:

Terminal window
ls ~/.claude/skills/ | grep swift

The skill should appear in the available skills list. I can now invoke it when working on Swift projects.

Core Usage Patterns

The Swift Expert skill activates automatically when I work on Swift files, but I can also invoke it directly with specific prompts:

"Use swift-expert for this implementation"
"Apply Swift best practices to this code"
"Review this Swift code for idiomatic patterns"

Common trigger phrases include:

  • “swift-expert”
  • “swift patterns”
  • “idiomatic swift”
  • “swift best practices”

Example 1: Building a SwiftUI View

When I create a SwiftUI view, I ask Swift Expert to guide the implementation:

Terminal window
user@mac:~/MyApp$ claude code

Then I prompt:

Use swift-expert to create a SwiftUI user list view with async data loading

The skill provides this implementation:

UserListView.swift
import SwiftUI
// MARK: - View Model
@MainActor
class UserListViewModel: ObservableObject {
@Published private(set) var users: [User] = []
@Published private(set) var isLoading = false
@Published private(set) var error: Error?
private let userService: UserServiceProtocol
init(userService: UserServiceProtocol = UserService()) {
self.userService = userService
}
// Async data loading with proper error handling
func loadUsers() async {
isLoading = true
defer { isLoading = false }
do {
users = try await userService.fetchUsers()
} catch {
self.error = error
}
}
}
// MARK: - View
struct UserListView: View {
@StateObject private var viewModel = UserListViewModel()
var body: some View {
NavigationView {
Group {
if viewModel.isLoading {
ProgressView("Loading...")
} else if let error = viewModel.error {
ErrorView(error: error) {
viewModel.loadUsers()
}
} else {
List(viewModel.users) { user in
UserRow(user: user)
}
}
}
.navigationTitle("Users")
.task {
await viewModel.loadUsers()
}
}
}
}
// MARK: - Components
struct UserRow: View {
let user: User
var body: some View {
HStack {
AsyncImage(url: user.avatarURL) { image in
image.resizable()
} placeholder: {
ProgressView()
}
.frame(width: 50, height: 50)
.clipShape(Circle())
VStack(alignment: .leading) {
Text(user.name)
.font(.headline)
Text(user.email)
.font(.caption)
.foregroundColor(.secondary)
}
}
}
}

I can see the skill applies Swift best practices:

  • Protocol-oriented design with UserServiceProtocol
  • Proper use of @MainActor for UI updates
  • Error handling with do-catch
  • View model separation for testability
  • MARK comments for code organization

Example 2: Implementing a Repository Pattern

When I need data layer code, I use Swift Expert to implement proper patterns:

Terminal window
user@mac:~/MyApp$ claude code

I ask:

Use swift-expert to implement a repository pattern for User data with Combine

The result:

UserRepository.swift
import Foundation
import Combine
// Protocol for dependency injection
protocol UserRepositoryProtocol {
func getUsers() -> AnyPublisher<[User], Error>
func getUser(id: UUID) -> AnyPublisher<User, Error>
func save(_ user: User) -> AnyPublisher<Void, Error>
}
// MARK: - Implementation
final class UserRepository: UserRepositoryProtocol {
private let networkService: NetworkServiceProtocol
private let cacheService: CacheServiceProtocol
private let cancellables = Set<AnyCancellable>()
init(
networkService: NetworkServiceProtocol,
cacheService: CacheServiceProtocol
) {
self.networkService = networkService
self.cacheService = cacheService
}
// Combine publishers for reactive data flow
func getUsers() -> AnyPublisher<[User], Error> {
// Try cache first
cacheService.getCachedUsers()
.catch { _ in
// Fallback to network if cache misses
self.networkService.fetchUsers()
.handleEvents(receiveOutput: { users in
// Update cache on success
self.cacheService.saveUsers(users)
})
}
.eraseToAnyPublisher()
}
func getUser(id: UUID) -> AnyPublisher<User, Error> {
cacheService.getCachedUser(id: id)
.catch { _ in
self.networkService.fetchUser(id: id)
.handleEvents(receiveOutput: { user in
self.cacheService.saveUser(user)
})
}
.eraseToAnyPublisher()
}
func save(_ user: User) -> AnyPublisher<Void, Error> {
networkService.saveUser(user)
.handleEvents(receiveOutput: {
self.cacheService.saveUser(user)
})
.eraseToAnyPublisher()
}
}
// MARK: - Dependency Injection Setup
extension UserRepository {
static func make() -> UserRepository {
let networkService = NetworkService()
let cacheService = CacheService()
return UserRepository(
networkService: networkService,
cacheService: cacheService
)
}
}

The key Swift patterns I notice:

  • Protocol abstraction for testability
  • Combine framework for reactive programming
  • Generic AnyPublisher return types
  • Factory method for dependency setup
  • Caching strategy with fallback
  • Value types over reference types where possible

Example 3: Custom Async Sequence

For advanced use cases, Swift Expert helps implement modern concurrency:

Terminal window
user@mac:~/MyApp$ claude code

I request:

Use swift-expert to create an async sequence for paginated API responses

The implementation:

PaginatedAsyncSequence.swift
import Foundation
// Custom AsyncSequence for pagination
struct PaginatedAsyncSequence<Element>: AsyncSequence {
typealias AsyncIterator = Paginator
let pageProvider: (Int) async throws -> [Element]
let pageSize: Int
func makeAsyncIterator() -> Paginator {
Paginator(
pageProvider: pageProvider,
pageSize: pageSize
)
}
actor Paginator: AsyncIteratorProtocol {
private var currentPage = 0
private var currentElements: [Element] = []
private var currentIndex = 0
private let pageProvider: (Int) async throws -> [Element]
private let pageSize: Int
init(pageProvider: @escaping (Int) async throws -> [Element], pageSize: Int) {
self.pageProvider = pageProvider
self.pageSize = pageSize
}
mutating func next() async throws -> Element? {
// Load next page if needed
if currentIndex >= currentElements.count {
let page = try await pageProvider(currentPage)
// End of sequence
guard page.count == pageSize else {
if currentIndex < page.count {
let element = page[currentIndex]
currentIndex += 1
return element
}
return nil
}
currentElements = page
currentIndex = 0
currentPage += 1
}
guard currentIndex < currentElements.count else {
return nil
}
let element = currentElements[currentIndex]
currentIndex += 1
return element
}
}
}
// MARK: - Usage Example
extension UserService {
func usersStream() -> PaginatedAsyncSequence<User> {
PaginatedAsyncSequence(
pageProvider: { page in
try await self.fetchUsers(page: page, limit: 20)
},
pageSize: 20
)
}
}
// Usage in SwiftUI
struct UserListView: View {
@State private var users: [User] = []
var body: some View {
List(users) { user in
Text(user.name)
}
.task {
// Stream all users automatically
for await user in userService.usersStream() {
users.append(user)
}
}
}
}

I can see Swift Expert applied advanced patterns:

  • Custom AsyncSequence implementation
  • Actor isolation for thread safety
  • Generic type parameter
  • Modern Swift concurrency with async/await
  • Automatic pagination handling
  • Clean integration with SwiftUI

Best Practices

1. Use protocols for abstraction

// Good: Protocol for testability
protocol DataServiceProtocol {
func fetch() async throws -> [Data]
}

2. Leverage Swift’s type system

// Good: Type-safe errors
enum DataError: Error {
case notFound
case invalidFormat
case networkFailed(underlying: Error)
}

3. Use value types

// Good: Struct for data models
struct User {
let id: UUID
var name: String
var email: String
}

4. Mark actors and main thread

// Good: Explicit concurrency
@MainActor
class ViewModel: ObservableObject {
@Published var data: [Data] = []
}
actor DataCache {
private var storage: [String: Data] = [:]
}

5. Handle optionals properly

// Good: Explicit optionals
func process(_ value: String?) {
guard let value = value else {
return
}
// Process value
}

DON’T: Common Mistakes

1. Don’t force unwrap

// Bad: Crash risk
let name = user.name!
// Good: Safe unwrapping
guard let name = user.name else { return }

2. Don’t use reference types unnecessarily

// Bad: Class for simple data
class User {
var name: String
}
// Good: Struct for data
struct User {
var name: String
}

3. Don’t ignore errors

// Bad: Silent failure
try? loadData()
// Good: Explicit error handling
do {
try await loadData()
} catch {
handleError(error)
}

4. Don’t overuse optionals

// Bad: Unnecessary optional
var name: String? = "Default"
// Good: Non-optional default
var name: String = "Default"

5. Don’t mix main actor and background work

// Bad: Blocking on main thread
@MainActor
func load() {
let data = try? fetchData() // Sync call
}
// Good: Async main actor
@MainActor
func load() async {
let data = try? await fetchData() // Async call
}

When to Use Swift Expert

I use Swift Expert in these scenarios:

For new Swift code: When starting a new feature, the skill ensures idiomatic patterns from the beginning.

For code reviews: The skill identifies Swift-specific issues and suggests improvements.

For learning: When exploring Swift frameworks like SwiftUI, Combine, or Swift Concurrency.

For refactoring: When modernizing older Swift code to use current best practices.

For debugging: When facing Swift-specific issues like memory management or concurrency bugs.

Swift Expert works well with other claude-skills:

  • ios-patterns: iOS-specific architecture and design patterns
  • tdd-workflow: Test-driven development for Swift projects
  • security-review: Security analysis for iOS apps
  • performance-optimization: Performance tuning for Swift code

Summary

In this post, I showed how to use Swift Expert skill in Claude Code for effective Swift development. The key point is knowing when to invoke the skill and how to apply its recommended patterns.

I covered installation, core usage patterns, and three practical examples: SwiftUI views, repository pattern, and async sequences. I also shared best practices and common mistakes to avoid.

When I use Swift Expert, I get code that follows Apple’s guidelines, leverages Swift’s type system, and uses modern concurrency patterns effectively. This helps me write better Swift code that’s maintainable, testable, and performant.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments