swift

Swift / iOS Development

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "swift" with this command: npx skills add nguyenhuuca/assessment/nguyenhuuca-assessment-swift

Swift / iOS Development

Project Setup

Swift Package Manager

Initialize new package

swift package init --type executable

Add dependencies to Package.swift

swift package update

Package.swift

// swift-tools-version: 5.10 import PackageDescription

let package = Package( name: "MyApp", platforms: [.iOS(.v17), .macOS(.v14)], products: [ .library(name: "MyApp", targets: ["MyApp"]), ], dependencies: [ // Add dependencies here ], targets: [ .target(name: "MyApp", dependencies: []), .testTarget(name: "MyAppTests", dependencies: ["MyApp"]), ] )

Xcode Project

Create new Xcode project via Xcode or:

Use SwiftUI App template for new projects

Target iOS 17+ for latest APIs

Type Patterns

Optionals

// Safe unwrapping if let user = optionalUser { print(user.name) }

// Guard for early exit guard let user = optionalUser else { return }

// Optional chaining let name = user?.profile?.displayName ?? "Anonymous"

// Nil coalescing let displayName = user?.name ?? "Guest"

Result Type

enum NetworkError: Error { case invalidURL case noData case decodingFailed }

func fetchUser(id: String) async -> Result<User, NetworkError> { guard let url = URL(string: "https://api.example.com/users/\(id)") else { return .failure(.invalidURL) }

do {
    let (data, _) = try await URLSession.shared.data(from: url)
    let user = try JSONDecoder().decode(User.self, from: data)
    return .success(user)
} catch {
    return .failure(.decodingFailed)
}

}

// Usage switch await fetchUser(id: "123") { case .success(let user): print("Got user: (user.name)") case .failure(let error): print("Error: (error)") }

Protocols & Extensions

protocol Identifiable { var id: UUID { get } }

protocol Displayable { var displayName: String { get } }

extension User: Identifiable, Displayable { var displayName: String { "(firstName) (lastName)" } }

Error Handling

// Throwing functions func loadConfig() throws -> Config { guard let data = FileManager.default.contents(atPath: configPath) else { throw ConfigError.fileNotFound } return try JSONDecoder().decode(Config.self, from: data) }

// Do-catch do { let config = try loadConfig() print(config) } catch ConfigError.fileNotFound { print("Config file missing") } catch { print("Unknown error: (error)") }

// Try? for optional result let config = try? loadConfig()

// Try! only when failure is impossible let bundledConfig = try! loadBundledConfig()

Async/Await Patterns

Basic Async

func fetchUsers() async throws -> [User] { let (data, _) = try await URLSession.shared.data(from: usersURL) return try JSONDecoder().decode([User].self, from: data) }

// Calling async functions Task { do { let users = try await fetchUsers() await MainActor.run { self.users = users } } catch { print("Failed: (error)") } }

Structured Concurrency

// Parallel execution async let users = fetchUsers() async let posts = fetchPosts() let (userList, postList) = try await (users, posts)

// Task groups func fetchAllUserData(ids: [String]) async throws -> [UserData] { try await withThrowingTaskGroup(of: UserData.self) { group in for id in ids { group.addTask { try await fetchUserData(id: id) } } return try await group.reduce(into: []) { $0.append($1) } } }

Actors

actor UserCache { private var cache: [String: User] = [:]

func get(_ id: String) -> User? {
    cache[id]
}

func set(_ user: User) {
    cache[user.id] = user
}

}

// Usage let cache = UserCache() await cache.set(user) let cached = await cache.get("123")

SwiftUI Patterns

View with State

struct ContentView: View { @State private var count = 0 @State private var username = ""

var body: some View {
    VStack(spacing: 16) {
        Text("Count: \(count)")
            .font(.title)

        Button("Increment") {
            count += 1
        }

        TextField("Username", text: $username)
            .textFieldStyle(.roundedBorder)
    }
    .padding()
}

}

Observable ViewModel

@Observable class UserViewModel { var users: [User] = [] var isLoading = false var error: Error?

func loadUsers() async {
    isLoading = true
    defer { isLoading = false }

    do {
        users = try await userService.fetchAll()
    } catch {
        self.error = error
    }
}

}

struct UserListView: View { @State private var viewModel = UserViewModel()

var body: some View {
    List(viewModel.users) { user in
        UserRow(user: user)
    }
    .task {
        await viewModel.loadUsers()
    }
    .overlay {
        if viewModel.isLoading {
            ProgressView()
        }
    }
}

}

Environment & Dependency Injection

// Define environment key struct UserServiceKey: EnvironmentKey { static let defaultValue: UserService = .live }

extension EnvironmentValues { var userService: UserService { get { self[UserServiceKey.self] } set { self[UserServiceKey.self] = newValue } } }

// Use in view struct ProfileView: View { @Environment(.userService) private var userService

var body: some View {
    // Use userService
}

}

Testing

Swift Testing (Swift 6+)

import Testing

@Suite("UserService Tests") struct UserServiceTests { let service = UserService()

@Test("creates user with valid email")
func createUser() async throws {
    let user = try await service.create(email: "test@example.com")
    #expect(user.email == "test@example.com")
}

@Test("throws on invalid email")
func invalidEmail() async {
    await #expect(throws: ValidationError.self) {
        try await service.create(email: "invalid")
    }
}

@Test("fetches user by ID", arguments: ["user1", "user2", "user3"])
func fetchUser(id: String) async throws {
    let user = try await service.fetch(id: id)
    #expect(user.id == id)
}

}

XCTest (Legacy)

import XCTest @testable import MyApp

final class UserServiceTests: XCTestCase { var service: UserService!

override func setUp() {
    super.setUp()
    service = UserService()
}

func testCreateUser() async throws {
    let user = try await service.create(email: "test@example.com")
    XCTAssertEqual(user.email, "test@example.com")
}

func testInvalidEmailThrows() async {
    do {
        _ = try await service.create(email: "invalid")
        XCTFail("Expected error")
    } catch {
        XCTAssertTrue(error is ValidationError)
    }
}

}

Tooling

SwiftLint (linting)

brew install swiftlint swiftlint lint swiftlint lint --fix

SwiftFormat (formatting)

brew install swiftformat swiftformat . swiftformat . --lint

Run tests

swift test xcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15'

Build

swift build xcodebuild build -scheme MyApp

fastlane (CI/CD)

brew install fastlane fastlane init fastlane ios test fastlane ios beta # Deploy to TestFlight

.swiftlint.yml

disabled_rules:

  • trailing_whitespace
  • line_length

opt_in_rules:

  • empty_count
  • empty_string

excluded:

  • Pods
  • .build

.swiftformat

--indent 4 --allman false --wraparguments before-first --wrapparameters before-first --self remove --importgrouping alphabetized

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

refactoring-code

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

implementing-code

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

python

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

optimizing-code

No summary provided by upstream source.

Repository SourceNeeds Review