← Back to list

swift
by onmyway133
My favorite Claude Code tools
⭐ 3🍴 0📅 Jan 12, 2026
SKILL.md
name: "Swift" description: "Swift and iOS development with modern patterns and best practices"
Swift
You are a Swift and iOS development expert. Apply these guidelines when working on Swift code.
Target Requirements
- Swift 6+ with modern Swift concurrency
- SwiftUI with
@Observablefor shared data - No third-party frameworks without explicit approval
- Avoid UIKit unless explicitly requested
- Follow Apple Human Interface Guidelines
Code Organization
Extension-Based Grouping
Organize related functionality using extensions:
// MARK: - Main View
struct BooksView: View {
@State private var books: [Book] = []
var body: some View {
List(books) { book in
BookCell(book: book)
}
}
}
// MARK: - Subviews
extension BooksView {
struct BookCell: View {
let book: Book
var body: some View {
HStack {
BookCover(url: book.coverURL)
BookInfo(book: book)
}
}
}
struct BookCover: View {
let url: URL?
var body: some View { /* ... */ }
}
struct BookInfo: View {
let book: Book
var body: some View { /* ... */ }
}
}
// MARK: - View Model
extension BooksView {
@Observable
@MainActor
final class ViewModel {
var books: [Book] = []
var isLoading = false
func loadBooks() async { /* ... */ }
}
}
File Structure
- Place each struct/class/enum in separate Swift files
- Don't break views into computed properties; use separate
Viewstructs - Organize by feature, not layer
Features/
├── Books/
│ ├── BooksView.swift
│ ├── BookDetailView.swift
│ └── Models/
├── Settings/
│ └── SettingsView.swift
└── Shared/
├── Components/
└── Extensions/
Naming Conventions
// Types: UpperCamelCase
struct UserProfile { }
enum NetworkError { }
protocol DataFetching { }
// Properties and methods: lowerCamelCase
var currentUser: User
func fetchUserData() async throws -> User
// Boolean properties: use assertion form
var isEnabled: Bool
var hasUnreadMessages: Bool
var canSubmit: Bool
// Collections: use plural nouns
var users: [User]
var selectedItems: Set<Item>
// Mutating vs non-mutating
func add(_ item: Item) // mutates
func adding(_ item: Item) -> [Item] // returns new
SwiftUI Patterns
State Management
// Local UI state only
@State private var searchText = ""
// Observable objects (iOS 17+) - prefer @Observable over ObservableObject
@Observable
@MainActor
final class ProfileViewModel {
var user: User?
var isLoading = false
}
// In views
@State private var viewModel = ProfileViewModel()
// For passed-in observable objects
@Bindable var viewModel: ProfileViewModel
Modern Modifiers (Use These)
.foregroundStyle(.primary) // NOT foregroundColor()
.clipShape(.rect(cornerRadius: 12)) // NOT cornerRadius()
.bold() // NOT fontWeight(.bold)
.scrollIndicators(.hidden) // to hide scroll bars
// Modern Tab API - NOT tabItem()
TabView {
Tab("Home", systemImage: "house") {
HomeView()
}
Tab("Settings", systemImage: "gear") {
SettingsView()
}
}
Deprecated Patterns to Avoid
// DON'T use single-parameter onChange
.onChange(of: value) { newValue in } // DEPRECATED
// DO use two-parameter version
.onChange(of: value) { oldValue, newValue in }
// For iOS 17+, prefer @Observable over ObservableObject
class MyViewModel: ObservableObject { } // Legacy (iOS 13-16)
@Observable class MyViewModel { } // Modern (iOS 17+)
Layout
// DON'T use UIScreen.main.bounds
let width = UIScreen.main.bounds.width // BAD
// DO use containerRelativeFrame or visualEffect
.containerRelativeFrame(.horizontal) { width, _ in
width * 0.8
}
// Prefer containerRelativeFrame() or visualEffect() over GeometryReader
// Use ImageRenderer instead of UIGraphicsImageRenderer
let renderer = ImageRenderer(content: myView)
if let image = renderer.uiImage { }
Buttons and Gestures
// DON'T use onTapGesture for buttons
Image(systemName: "plus")
.onTapGesture { action() } // BAD
// DO use Button with labels
Button {
action()
} label: {
Label("Add Item", systemImage: "plus")
}
// Only use onTapGesture when tracking tap location or count
Navigation
// Modern navigation with type-safe destinations
NavigationStack {
List(items) { item in
NavigationLink(value: item) {
ItemRow(item: item)
}
}
.navigationDestination(for: Item.self) { item in
ItemDetailView(item: item)
}
}
Collections
// DO use enumerated directly
ForEach(Array(items.enumerated()), id: \.element.id) { index, item in
Text("\(index): \(item.name)")
}
// DON'T convert to array first unnecessarily
Modern Swift APIs
Concurrency
// Modern sleep - NOT Task.sleep(nanoseconds:)
try await Task.sleep(for: .seconds(1))
// NEVER use DispatchQueue.main.async()
DispatchQueue.main.async { } // BAD
// DO use MainActor
await MainActor.run { }
// or mark with @MainActor
// All @Observable classes should be @MainActor
@Observable
@MainActor
final class ViewModel { }
Modern Foundation
// Directory access
let documents = URL.documentsDirectory
let cache = URL.cachesDirectory
// Path manipulation
let file = documents.appending(path: "data.json")
// String operations - NOT replacingOccurrences(of:with:)
let result = text.replacing("old", with: "new")
// Text filtering - NOT contains()
items.filter { $0.name.localizedStandardContains(searchText) }
Text Formatting
// Use format parameter - NOT C-style or NumberFormatter
Text(price, format: .currency(code: "USD"))
Text(date, format: .dateTime.month().day())
Text(count, format: .number.precision(.fractionLength(2)))
Static Member Lookup
// Prefer static members over initializers
.buttonStyle(.borderedProminent) // NOT BorderedProminentButtonStyle()
.clipShape(.capsule) // NOT Capsule()
.clipShape(.circle) // NOT Circle()
.background(.ultraThinMaterial)
SwiftUI Colors
// DON'T use UIKit colors in SwiftUI
Color(UIColor.systemBackground) // BAD
// DO use SwiftUI colors
Color(.systemBackground) // OK
Color.primary
Color.secondary
Dynamic Type
// DON'T override Dynamic Type
.font(.system(size: 16)) // BAD - fixed size
// DO respect system font sizing
.font(.body)
.font(.headline)
// Avoid hard-coded padding and spacing values
SwiftData
Basic Setup
@Model
final class Book {
var title: String
var author: String
var publishedDate: Date
var rating: Int?
@Relationship(deleteRule: .cascade)
var chapters: [Chapter]?
init(title: String, author: String, publishedDate: Date) {
self.title = title
self.author = author
self.publishedDate = publishedDate
}
}
CloudKit Compatibility
When using iCloud sync:
- NEVER use
@Attribute(.unique) - All properties need default values or be optional
- Mark ALL relationships as optional
Error Handling
// Define specific error types
enum DataError: LocalizedError {
case networkUnavailable
case invalidResponse(statusCode: Int)
case decodingFailed(underlying: Error)
var errorDescription: String? {
switch self {
case .networkUnavailable:
return "Network connection unavailable"
case .invalidResponse(let code):
return "Server returned error \(code)"
case .decodingFailed:
return "Failed to process server response"
}
}
}
// Avoid force try and force unwrap (except truly unrecoverable cases)
do {
let data = try await fetchData()
let result = try decoder.decode(Response.self, from: data)
} catch {
logger.error("Failed to load: \(error)")
throw DataError.decodingFailed(underlying: error)
}
Testing
Swift Testing Framework
import Testing
struct AuthenticationTests {
@Test("User can log in with valid credentials")
func successfulLogin() async throws {
let auth = AuthService()
let result = try await auth.login(email: "test@example.com", password: "valid")
#expect(result.isAuthenticated)
}
@Test("Login fails with wrong password")
func failedLogin() async {
let auth = AuthService()
await #expect(throws: AuthError.invalidCredentials) {
try await auth.login(email: "test@example.com", password: "wrong")
}
}
}
Testing Guidelines
- Write unit tests for core application logic
- UI tests only when unit tests aren't feasible
- Place view logic in view models for testability
iOS Version Features
iOS 17+
@Observablemacro replacesObservableObject@Bindablefor bindings to observable objects- SwiftData for persistence
- TipKit for onboarding hints
iOS 18+
- Enhanced SwiftData with
#Indexand#Unique - Control Center widgets
@Previewablemacro for simpler previews
iOS 26+
- Liquid Glass design system
- New translucent materials
- Modern Tab API
Things to Avoid
- Force unwrapping - Use
if let,guard let, or nil coalescing - AnyView - Use
@ViewBuilderor concrete types - GeometryReader - Try
containerRelativeFramefirst - UIScreen.main.bounds - Use proper layout APIs
- ObservableObject - Use
@Observableinstead (iOS 17+) - DispatchQueue.main.async - Use
@MainActor - Hard-coded sizes - Respect Dynamic Type
- UIKit colors - Use SwiftUI colors
- Computed property views - Use separate View structs
- Single-param onChange - Use two-parameter version
Security
- NEVER commit secrets, API keys, or configuration data
- Use environment variables or secure storage
- Follow App Store Review Guidelines
Before Committing
- Run SwiftLint; fix all warnings and errors
- Ensure no force unwraps without justification
- Verify async code uses proper actors
- Check that views support Dynamic Type
- Write tests for business logic
- Add documentation comments as needed
Score
Total Score
60/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
✓最近の活動
3ヶ月以内に更新
+5
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
○言語
プログラミング言語が設定されている
0/5
✓タグ
1つ以上のタグが設定されている
+5
Reviews
💬
Reviews coming soon

