swift-fundamentals
Swift Fundamentals
Comprehensive guide to Swift 6.x language features, best practices, macros, and project configuration for iOS 26 and macOS Tahoe development.
Prerequisites
- Xcode 26+ or Swift 6.x toolchain
- macOS 15.5+ (Sequoia) for full iOS 26 support
Swift Version Check
swift --version
# Swift version 6.x
Swift 6.x Key Features
Swift 6.0 - Major Changes
- Complete Concurrency Checking - Strict data-race safety by default
- Typed Throws - Functions can specify error types:
throws(MyError) - Noncopyable Types -
~Copyablefor unique ownership - Pack Iteration - Iterate over parameter packs
- 128-bit Integer Types -
Int128andUInt128 - count(where:) - Count elements matching predicate
Swift 6.2 - Recent Improvements
- Approachable Concurrency - Easier adoption path
- Single-threaded by default - New
defaultIsolationsetting - Observations Async Sequence - Stream state changes
- Pre-built swift-syntax - Faster macro compilation
- InlineArray - Fixed-size inline storage
Swift 6.3 - Latest (2025)
- Enhanced Type Inference - Better generic inference
- Improved Error Messages - Clearer diagnostics
- Performance Optimizations - Faster compilation
Core Macros
@Observable (iOS 17+)
Modern replacement for ObservableObject. Automatically tracks property access.
import Observation
@Observable
class UserSettings {
var username: String = ""
var isLoggedIn: Bool = false
var preferences: Preferences = Preferences()
// Computed properties are also tracked
var displayName: String {
isLoggedIn ? username : "Guest"
}
}
// Usage in SwiftUI
struct SettingsView: View {
var settings: UserSettings // No @ObservedObject needed
var body: some View {
Text(settings.displayName)
// View automatically updates when displayName changes
}
}
Key Differences from ObservableObject:
- No
@Publishedproperty wrappers needed - No
objectWillChangepublisher - Finer-grained updates (per-property, not whole object)
- Use
@Bindablefor two-way bindings
struct EditView: View {
@Bindable var settings: UserSettings
var body: some View {
TextField("Username", text: $settings.username)
}
}
@Model (SwiftData)
Declares a SwiftData model with automatic persistence.
import SwiftData
@Model
class Note {
var title: String
var content: String
var createdAt: Date
var tags: [Tag]? // Optional relationship for CloudKit
init(title: String, content: String = "") {
self.title = title
self.content = content
self.createdAt = Date()
}
}
@Model
class Tag {
var name: String
var notes: [Note]? // Inverse relationship
init(name: String) {
self.name = name
}
}
Important for CloudKit Sync:
- All relationships must be optional
- No
@Attribute(.unique)constraints - Default values required for non-optional properties
@MainActor
Ensures code runs on the main thread/actor.
@MainActor
class ViewModel {
var items: [Item] = []
var isLoading = false
func loadItems() async {
isLoading = true
defer { isLoading = false }
// Network call can be off main actor
let fetched = await fetchItems()
// Assignment happens on main actor
items = fetched
}
nonisolated func fetchItems() async -> [Item] {
// This can run on any thread
try? await URLSession.shared.data(from: url)
// ...
}
}
@Generable (Foundation Models - iOS 26)
Enables structured AI output generation.
import FoundationModels
@Generable
struct MovieRecommendation {
var title: String
var year: Int
var genre: String
var reason: String
}
// Usage
let session = LanguageModelSession()
let recommendation: MovieRecommendation = try await session.respond(
to: "Recommend a sci-fi movie from the 2020s"
)
@Test (Swift Testing)
Marks a function as a test case.
import Testing
@Test("User can create account with valid email")
func createAccountWithValidEmail() async throws {
let result = try await authService.createAccount(email: "test@example.com")
#expect(result.success)
#expect(result.user?.email == "test@example.com")
}
@Test("Password validation", arguments: [
("abc", false),
("abc12345", true),
("ABC12345!", true)
])
func validatePassword(password: String, expected: Bool) {
#expect(validator.isValid(password) == expected)
}
Property Wrappers
SwiftUI Property Wrappers
struct ContentView: View {
// Local state - view owns this value
@State private var count = 0
// Two-way binding from parent
@Binding var selectedTab: Int
// Environment value from system or parent
@Environment(\.colorScheme) var colorScheme
// Custom environment object
@Environment(AppState.self) var appState
// SwiftData query
@Query(sort: \Note.createdAt, order: .reverse)
var notes: [Note]
// Focus state for text fields
@FocusState private var isFocused: Bool
// Namespace for matched geometry effects
@Namespace private var animation
var body: some View {
// ...
}
}
@Bindable (iOS 17+)
Creates bindings to @Observable properties.
struct EditorView: View {
@Bindable var document: Document // Document is @Observable
var body: some View {
TextEditor(text: $document.content)
Toggle("Published", isOn: $document.isPublished)
}
}
@AppStorage
Persists values to UserDefaults.
struct SettingsView: View {
@AppStorage("hasCompletedOnboarding") var hasCompletedOnboarding = false
@AppStorage("preferredTheme") var preferredTheme = "system"
@AppStorage("notificationsEnabled") var notificationsEnabled = true
var body: some View {
Toggle("Notifications", isOn: $notificationsEnabled)
}
}
@SceneStorage
Persists view state per scene (for state restoration).
struct DocumentView: View {
@SceneStorage("selectedDocumentID") var selectedDocumentID: String?
@SceneStorage("scrollPosition") var scrollPosition: Double = 0
var body: some View {
// State restored when scene is recreated
}
}
Package.swift Configuration
Basic Package
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
name: "MyApp",
platforms: [
.iOS(.v26),
.macOS(.v26)
],
products: [
.library(name: "MyApp", targets: ["MyApp"])
],
dependencies: [
// External dependencies
],
targets: [
.target(
name: "MyApp",
dependencies: [],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
]
),
.testTarget(
name: "MyAppTests",
dependencies: ["MyApp"]
)
]
)
With Dependencies
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
name: "MyApp",
platforms: [
.iOS(.v26),
.macOS(.v26)
],
products: [
.library(name: "MyApp", targets: ["MyApp"])
],
dependencies: [
.package(url: "https://github.com/apple/swift-algorithms", from: "1.2.0"),
.package(url: "https://github.com/apple/swift-collections", from: "1.1.0"),
.package(url: "https://github.com/apple/swift-async-algorithms", from: "1.0.0")
],
targets: [
.target(
name: "MyApp",
dependencies: [
.product(name: "Algorithms", package: "swift-algorithms"),
.product(name: "Collections", package: "swift-collections"),
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms")
]
)
]
)
Strict Concurrency Settings
swiftSettings: [
// Full Swift 6 concurrency
.enableExperimentalFeature("StrictConcurrency"),
// Or gradual adoption
.swiftLanguageMode(.v6),
// Enable upcoming features
.enableUpcomingFeature("ExistentialAny"),
.enableUpcomingFeature("InternalImportsByDefault")
]
Project Structure
Recommended Layout
MyApp/
├── Package.swift
├── Sources/
│ └── MyApp/
│ ├── App/
│ │ ├── MyAppApp.swift
│ │ └── AppState.swift
│ ├── Models/
│ │ ├── Note.swift
│ │ ├── Tag.swift
│ │ └── User.swift
│ ├── Views/
│ │ ├── ContentView.swift
│ │ ├── Notes/
│ │ │ ├── NoteListView.swift
│ │ │ ├── NoteDetailView.swift
│ │ │ └── NoteEditorView.swift
│ │ └── Settings/
│ │ └── SettingsView.swift
│ ├── Services/
│ │ ├── NetworkService.swift
│ │ └── StorageService.swift
│ ├── Utilities/
│ │ ├── Extensions/
│ │ └── Helpers/
│ └── Resources/
│ ├── Localizable.xcstrings
│ └── Assets.xcassets
└── Tests/
└── MyAppTests/
├── ModelTests/
├── ServiceTests/
└── ViewTests/
App Entry Point
import SwiftUI
import SwiftData
@main
struct MyAppApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(for: [Note.self, Tag.self])
}
}
With Custom Container Configuration
@main
struct MyAppApp: App {
let container: ModelContainer
init() {
let schema = Schema([Note.self, Tag.self])
let config = ModelConfiguration(
schema: schema,
isStoredInMemoryOnly: false,
cloudKitDatabase: .automatic // Enable iCloud sync
)
do {
container = try ModelContainer(for: schema, configurations: config)
} catch {
fatalError("Failed to configure SwiftData: \(error)")
}
}
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(container)
}
}
Modern Swift Patterns
Result Builders
@resultBuilder
struct HTMLBuilder {
static func buildBlock(_ components: String...) -> String {
components.joined()
}
static func buildOptional(_ component: String?) -> String {
component ?? ""
}
static func buildEither(first component: String) -> String {
component
}
static func buildEither(second component: String) -> String {
component
}
}
func html(@HTMLBuilder content: () -> String) -> String {
"<html>\(content())</html>"
}
let page = html {
"<head><title>Hello</title></head>"
"<body>"
if showHeader {
"<h1>Welcome</h1>"
}
"<p>Content here</p>"
"</body>"
}
Typed Throws (Swift 6)
enum NetworkError: Error {
case invalidURL
case noData
case decodingFailed
}
func fetchUser(id: Int) throws(NetworkError) -> User {
guard let url = URL(string: "https://api.example.com/users/\(id)") else {
throw .invalidURL
}
// ...
}
// Caller knows exactly what errors to handle
do {
let user = try fetchUser(id: 123)
} catch .invalidURL {
// Handle invalid URL
} catch .noData {
// Handle no data
} catch .decodingFailed {
// Handle decoding error
}
Noncopyable Types (Swift 6)
struct UniqueResource: ~Copyable {
let handle: Int
init(handle: Int) {
self.handle = handle
}
deinit {
// Clean up resource
closeHandle(handle)
}
consuming func close() {
// Explicitly consume the resource
}
}
func useResource() {
let resource = UniqueResource(handle: 42)
// resource cannot be copied
// processResource(resource) // This moves resource
// resource.doSomething() // Error: resource was moved
}
Parameter Packs (Swift 6)
func all<each T: Equatable>(
_ values: repeat each T,
equalTo comparisons: repeat each T
) -> Bool {
for (value, comparison) in repeat (each values, each comparisons) {
if value != comparison {
return false
}
}
return true
}
let result = all(1, "hello", true, equalTo: 1, "hello", true) // true
Error Handling Best Practices
Define Domain Errors
enum AppError: LocalizedError {
case networkUnavailable
case unauthorized
case notFound(resource: String)
case validationFailed(field: String, reason: String)
case unknown(underlying: Error)
var errorDescription: String? {
switch self {
case .networkUnavailable:
return "Network connection unavailable"
case .unauthorized:
return "You are not authorized to perform this action"
case .notFound(let resource):
return "\(resource) was not found"
case .validationFailed(let field, let reason):
return "\(field): \(reason)"
case .unknown(let error):
return error.localizedDescription
}
}
}
Result Type Pattern
func fetchData() async -> Result<Data, AppError> {
guard NetworkMonitor.shared.isConnected else {
return .failure(.networkUnavailable)
}
do {
let data = try await networkService.fetch()
return .success(data)
} catch {
return .failure(.unknown(underlying: error))
}
}
// Usage
switch await fetchData() {
case .success(let data):
process(data)
case .failure(let error):
showError(error)
}
Extensions Best Practices
Organize by Functionality
// String+Validation.swift
extension String {
var isValidEmail: Bool {
let pattern = #"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$"#
return range(of: pattern, options: .regularExpression) != nil
}
var isValidPassword: Bool {
count >= 8 &&
range(of: "[A-Z]", options: .regularExpression) != nil &&
range(of: "[0-9]", options: .regularExpression) != nil
}
}
// Date+Formatting.swift
extension Date {
var relativeDescription: String {
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .short
return formatter.localizedString(for: self, relativeTo: Date())
}
var iso8601String: String {
ISO8601DateFormatter().string(from: self)
}
}
// View+Modifiers.swift
extension View {
func cardStyle() -> some View {
modifier(CardModifier())
}
@ViewBuilder
func `if`<Content: View>(_ condition: Bool, transform: (Self) -> Content) -> some View {
if condition {
transform(self)
} else {
self
}
}
}
Code Quality
SwiftLint Configuration
# .swiftlint.yml
included:
- Sources
- Tests
excluded:
- .build
- Package.swift
disabled_rules:
- trailing_whitespace
- line_length
opt_in_rules:
- empty_count
- explicit_init
- closure_spacing
- overridden_super_call
- redundant_nil_coalescing
- private_outlet
- nimble_operator
- attributes
- operator_usage_whitespace
- closure_end_indentation
- first_where
- object_literal
- number_separator
- prohibited_super_call
- fatal_error_message
- weak_delegate
line_length:
warning: 120
error: 200
type_body_length:
warning: 300
error: 500
file_length:
warning: 500
error: 1000
identifier_name:
min_length: 2
max_length: 50
Swift Format Configuration
// .swift-format
{
"version": 1,
"lineLength": 120,
"indentation": {
"spaces": 4
},
"tabWidth": 4,
"maximumBlankLines": 1,
"respectsExistingLineBreaks": true,
"lineBreakBeforeControlFlowKeywords": false,
"lineBreakBeforeEachArgument": false
}
Official Resources
More from bluewaves-creations/bluewaves-skills
photographer-testino
Generate images in Mario Testino's glamorous vibrant style. Use when users ask for Testino style, high fashion glamour, bold saturated colors, warm luxurious photography, dynamic sensual energy.
35photographer-lindbergh
Generate images in Peter Lindbergh's iconic black and white style. Use when users ask for Lindbergh style, raw authentic beauty, emotional B&W portraits, supermodel aesthetic, or unretouched natural photography.
30photographer-lachapelle
Generate images in David LaChapelle's surreal pop art style. Use when users ask for LaChapelle style, pop surrealism, hyper-saturated colors, theatrical staging, baroque maximalism, kitsch aesthetic.
24epub-creator
Create production-quality EPUB 3 ebooks from markdown and images with automated QA, formatting fixes, and validation. Use when creating ebooks, converting markdown to EPUB, or compiling chapters into a publishable book. Handles markdown quirks, generates TOC, adds covers, and validates output automatically.
22photographer-vonunwerth
Generate images in Ellen von Unwerth's playful vintage style. Use when users ask for von Unwerth style, playful sensuality, vintage film noir, whimsical feminine photography, retro glamour, narrative storytelling.
19photographer-ritts
Generate images in Herb Ritts' sculptural black and white style. Use when users ask for Ritts style, classical Greek aesthetic, sculptural body photography, California golden hour, minimalist athletic portraits.
18