Files
english/.opencode/skills/mobile-development/references/mobile-ios.md
2026-04-12 01:06:31 +07:00

10 KiB

iOS Native Development

Complete guide to iOS development with Swift and SwiftUI (2024-2025).

Swift 6 Overview

Key Features

  • Data race safety: Compile-time detection (default in Swift 6)
  • Concurrency: async/await, actors, @MainActor
  • Macro system: Code generation at compile time
  • Move semantics: Ownership optimization
  • Enhanced generics: More powerful type system

Modern Swift Patterns

Async/Await:

func fetchUser(id: String) async throws -> User {
    let (data, _) = try await URLSession.shared.data(from: url)
    return try JSONDecoder().decode(User.self, from: data)
}

// Usage
Task {
    do {
        let user = try await fetchUser(id: "123")
        self.user = user
    } catch {
        self.error = error
    }
}

Actors (Thread-safe classes):

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

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

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

SwiftUI vs UIKit

When to Use SwiftUI

New projects (iOS 13+) Declarative UI preferred Fast iteration needed Cross-platform (macOS, watchOS, tvOS) 40% less code vs UIKit

When to Use UIKit

Legacy app maintenance Complex customizations Fine-grained control needed Specific UIKit features required Pre-iOS 13 support

SwiftUI Basics

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

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

            Button("Increment") {
                count += 1
            }
            .buttonStyle(.borderedProminent)
        }
        .padding()
    }
}

Property Wrappers:

  • @State: View-local state
  • @Binding: Two-way binding
  • @StateObject: Observable object owner
  • @ObservedObject: Observable object reference
  • @EnvironmentObject: Dependency injection
  • @Published: Observable property

Architecture Patterns

// Model
struct User: Identifiable, Codable {
    let id: String
    let name: String
    let email: String
}

// ViewModel
@MainActor
class UserViewModel: ObservableObject {
    @Published var users: [User] = []
    @Published var isLoading = false
    @Published var error: Error?

    private let repository: UserRepository

    init(repository: UserRepository = UserRepository()) {
        self.repository = repository
    }

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

        do {
            users = try await repository.fetchUsers()
        } catch {
            self.error = error
        }
    }
}

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

    var body: some View {
        List(viewModel.users) { user in
            Text(user.name)
        }
        .task {
            await viewModel.loadUsers()
        }
    }
}

TCA (The Composable Architecture)

When to use:

  • Complex state management
  • Predictable state updates
  • Excellent testing
  • Enterprise apps

Trade-offs:

  • Steeper learning curve
  • More boilerplate
  • Excellent for large teams

Performance Optimization

Compiler Optimizations

1. Use final classes:

final class FastClass {
    // Compiler can optimize (no dynamic dispatch)
}

2. Private methods:

private func optimize() {
    // Compiler can inline
}

3. Whole-module optimization:

# Build Settings
SWIFT_WHOLE_MODULE_OPTIMIZATION = YES

Memory Management

ARC (Automatic Reference Counting):

class Parent {
    var child: Child?
}

class Child {
    weak var parent: Parent?  // Weak to avoid retain cycle
}

Common Retain Cycles:

// ❌ Bad: Retain cycle
class ViewController: UIViewController {
    var completion: (() -> Void)?

    func setup() {
        completion = {
            self.doSomething()  // Strong capture
        }
    }
}

// ✅ Good: Weak self
class ViewController: UIViewController {
    var completion: (() -> Void)?

    func setup() {
        completion = { [weak self] in
            self?.doSomething()
        }
    }
}

SwiftUI Performance

1. Use const modifiers:

Text("Hello")  // Recreated on every render

vs

Text("Hello")
    .font(.title)  // Modifier creates new view

// Better: Extract static views
let titleText = Text("Hello").font(.title)

2. Avoid expensive computations:

struct ExpensiveView: View {
    let data: [Item]

    // Computed every render
    var sortedData: [Item] {
        data.sorted()  // ❌ Bad
    }

    // Better: Cache with @State or pass sorted
}

Testing Strategies

XCTest (Unit Testing)

import XCTest
@testable import MyApp

final class UserViewModelTests: XCTestCase {
    var viewModel: UserViewModel!
    var mockRepository: MockUserRepository!

    override func setUp() {
        super.setUp()
        mockRepository = MockUserRepository()
        viewModel = UserViewModel(repository: mockRepository)
    }

    func testLoadUsers() async throws {
        // Given
        let expectedUsers = [User(id: "1", name: "Test", email: "test@example.com")]
        mockRepository.usersToReturn = expectedUsers

        // When
        await viewModel.loadUsers()

        // Then
        XCTAssertEqual(viewModel.users, expectedUsers)
        XCTAssertFalse(viewModel.isLoading)
        XCTAssertNil(viewModel.error)
    }
}

XCUITest (UI Testing)

import XCTest

final class LoginUITests: XCTestCase {
    let app = XCUIApplication()

    override func setUp() {
        super.setUp()
        app.launch()
    }

    func testLoginFlow() {
        let emailField = app.textFields["emailField"]
        emailField.tap()
        emailField.typeText("test@example.com")

        let passwordField = app.secureTextFields["passwordField"]
        passwordField.tap()
        passwordField.typeText("password123")

        app.buttons["loginButton"].tap()

        XCTAssertTrue(app.staticTexts["Welcome"].waitForExistence(timeout: 5))
    }
}

Target Coverage:

  • Unit tests: 70-80%+
  • Critical paths: 100%
  • UI tests: Key user flows only (slow)

iOS-Specific Features

WidgetKit

import WidgetKit
import SwiftUI

struct SimpleWidget: Widget {
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: "SimpleWidget", provider: Provider()) { entry in
            SimpleWidgetView(entry: entry)
        }
        .configurationDisplayName("My Widget")
        .description("This is my widget")
        .supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
    }
}

Live Activities (iOS 16.1+)

import ActivityKit

struct OrderAttributes: ActivityAttributes {
    struct ContentState: Codable, Hashable {
        var status: String
        var estimatedTime: Date
    }

    var orderId: String
}

// Start activity
let attributes = OrderAttributes(orderId: "123")
let initialState = OrderAttributes.ContentState(
    status: "Preparing",
    estimatedTime: Date().addingTimeInterval(1800)
)

let activity = try Activity.request(
    attributes: attributes,
    contentState: initialState
)

App Clips

Characteristics:

  • <10MB size limit
  • Fast, lightweight experiences
  • No installation required
  • Invoked via NFC, QR, Safari, Maps

Human Interface Guidelines (HIG)

Navigation Patterns

Tab Bar:

  • 2-5 top-level sections
  • Bottom placement
  • Always visible
  • Immediate navigation

Navigation Bar:

  • Hierarchical navigation
  • Back button automatic
  • Title and actions
  • Large/inline title modes

Modal Presentation:

  • Interrupting tasks
  • Self-contained flow
  • Clear dismiss action
  • Use sparingly

Design Principles

Clarity:

  • Legible text (minimum 11pt)
  • Sufficient contrast (WCAG AA)
  • Precise icons

Deference:

  • Content first, UI second
  • Translucent backgrounds
  • Minimal UI elements

Depth:

  • Layering (sheets, overlays)
  • Visual hierarchy
  • Motion provides meaning

Colors

System Colors:

Color.primary      // Adaptive black/white
Color.secondary    // Gray
Color.accentColor  // App tint color
Color(uiColor: .systemBlue)
Color(uiColor: .label)

Dark Mode:

// Automatic
Color.primary  // Adapts to light/dark

// Custom
Color("CustomColor")  // Define in Assets.xcassets

SF Symbols

Image(systemName: "star.fill")
    .foregroundColor(.yellow)
    .font(.title)

// Rendering modes
Image(systemName: "heart.fill")
    .symbolRenderingMode(.multicolor)

App Store Requirements (2024-2025)

SDK Requirements

  • Current: Xcode 15+ with iOS 17 SDK (required as of April 2024)
  • Upcoming: Xcode 16+ with iOS 18 SDK (recommended for 2025 submissions)

Privacy

  • Privacy manifest: Required for third-party SDKs
  • Tracking permission: ATT framework for advertising
  • Privacy nutrition labels: Accurate data collection info
  • Account deletion: In-app deletion required

Capabilities

  • Sandbox: All apps sandboxed
  • Entitlements: Request only needed capabilities
  • Background modes: Justify background usage
  • HealthKit: Privacy-sensitive, strict review

Submission Checklist

App icons (all required sizes) Screenshots (all device sizes) App description and keywords Privacy policy URL Support URL Age rating questionnaire Export compliance Test on real devices No crashes or major bugs

Common Pitfalls

  1. Strong reference cycles: Use [weak self] in closures
  2. Main thread blocking: Use async/await, avoid sync operations
  3. Large images: Resize before displaying
  4. Unhandled errors: Always handle async throws
  5. Ignoring safe areas: Use .ignoresSafeArea() intentionally
  6. Not testing dark mode: Design for both appearances
  7. Hardcoded strings: Use localization from start
  8. Memory leaks: Profile with Instruments regularly

Resources

Official:

Community: