āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž SwiftUI: āļāļēāļĢāļ›āļĢāļąāļšāđāļ•āđˆāļ‡ LazyVStack āđāļĨāļ°āļĢāļēāļĒāļāļēāļĢāļ—āļĩāđˆāļ‹āļąāļšāļ‹āđ‰āļ­āļ™

āđ€āļ—āļ„āļ™āļīāļ„āļāļēāļĢāļ›āļĢāļąāļšāđāļ•āđˆāļ‡āļŠāļģāļŦāļĢāļąāļš LazyVStack āđāļĨāļ°āļĢāļēāļĒāļāļēāļĢ SwiftUI āļĨāļ”āļāļēāļĢāđƒāļŠāđ‰āļŦāļ™āđˆāļ§āļĒāļ„āļ§āļēāļĄāļˆāļģ āļ›āļĢāļąāļšāļ›āļĢāļļāļ‡āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļāļēāļĢāđ€āļĨāļ·āđˆāļ­āļ™ āđāļĨāļ°āļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ”āļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒ

āļāļēāļĢāļ›āļĢāļąāļšāđāļ•āđˆāļ‡āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž SwiftUI LazyVStack āđāļĨāļ°āļĢāļēāļĒāļāļēāļĢāļ—āļĩāđˆāļ‹āļąāļšāļ‹āđ‰āļ­āļ™

āļĢāļēāļĒāļāļēāļĢāđ€āļ›āđ‡āļ™āļŦāļ™āļķāđˆāļ‡āđƒāļ™āļŠāđˆāļ§āļ™āļ›āļĢāļ°āļāļ­āļšāļ—āļĩāđˆāđƒāļŠāđ‰āļšāđˆāļ­āļĒāļ—āļĩāđˆāļŠāļļāļ”āđƒāļ™āđāļ­āļ›āļžāļĨāļīāđ€āļ„āļŠāļąāļ™ iOS LazyVStack āđāļĨāļ° List āļ‚āļ­āļ‡ SwiftUI āđƒāļŦāđ‰āđ‚āļ‹āļĨāļđāļŠāļąāļ™āļ—āļĩāđˆāļĄāļĩāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāđƒāļ™āļāļēāļĢāđāļŠāļ”āļ‡āļ„āļ­āļĨāđ€āļĨāļāļŠāļąāļ™āļ‚āđ‰āļ­āļĄāļđāļĨ āđāļ•āđˆāļāļēāļĢāđƒāļŠāđ‰āļ‡āļēāļ™āļ—āļĩāđˆāđ„āļĄāđˆāļ–āļđāļāļ•āđ‰āļ­āļ‡āļ­āļēāļˆāļĨāļ”āļ›āļĢāļ°āļŠāļšāļāļēāļĢāļ“āđŒāļœāļđāđ‰āđƒāļŠāđ‰āđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āļĢāļ§āļ”āđ€āļĢāđ‡āļ§ āļāļēāļĢāđ€āļ‚āđ‰āļēāđƒāļˆāļāļĨāđ„āļāļ āļēāļĒāđƒāļ™āļ‚āļ­āļ‡āļŠāđˆāļ§āļ™āļ›āļĢāļ°āļāļ­āļšāđ€āļŦāļĨāđˆāļēāļ™āļĩāđ‰āļŠāđˆāļ§āļĒāļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ”āļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāđāļĨāļ°āļŠāļĢāđ‰āļēāļ‡āļ­āļīāļ™āđ€āļ—āļ­āļĢāđŒāđ€āļŸāļ‹āļ—āļĩāđˆāļĨāļ·āđˆāļ™āđ„āļŦāļĨ

āļŠāļīāđˆāļ‡āļ—āļĩāđˆāļšāļ—āļ„āļ§āļēāļĄāļ™āļĩāđ‰āļ„āļĢāļ­āļšāļ„āļĨāļļāļĄ

āļšāļ—āļ„āļ§āļēāļĄāļ™āļĩāđ‰āļ™āļģāđ€āļŠāļ™āļ­āđ€āļ—āļ„āļ™āļīāļ„āļāļēāļĢāļ›āļĢāļąāļšāđāļ•āđˆāļ‡āļ—āļĩāđˆāļˆāļģāđ€āļ›āđ‡āļ™āļŠāļģāļŦāļĢāļąāļšāļĢāļēāļĒāļāļēāļĢ SwiftUI: lazy loading āļāļēāļĢāļĢāļĩāđ„āļ‹āđ€āļ„āļīāļĨāļ§āļīāļ§ āļāļēāļĢāļˆāļąāļ”āļāļēāļĢāļ•āļąāļ§āļĢāļ°āļšāļļ āđāļĨāļ°āļĢāļđāļ›āđāļšāļšāļ‚āļąāđ‰āļ™āļŠāļđāļ‡āļŠāļģāļŦāļĢāļąāļšāļŠāļļāļ”āļ‚āđ‰āļ­āļĄāļđāļĨāļ‚āļ™āļēāļ”āđƒāļŦāļāđˆ

āļ—āļģāļ„āļ§āļēāļĄāđ€āļ‚āđ‰āļēāđƒāļˆ Lazy Loading āđƒāļ™ SwiftUI

Lazy loading āļˆāļ°āļŠāļĢāđ‰āļēāļ‡āļ§āļīāļ§āđ€āļ‰āļžāļēāļ°āđ€āļĄāļ·āđˆāļ­āļ›āļĢāļēāļāļāļšāļ™āļŦāļ™āđ‰āļēāļˆāļ­āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™ āļ•āđˆāļēāļ‡āļˆāļēāļ VStack āļ—āļĩāđˆāļŠāļĢāđ‰āļēāļ‡āļ§āļīāļ§āļĨāļđāļāļ—āļąāđ‰āļ‡āļŦāļĄāļ”āļ—āļąāļ™āļ—āļĩ LazyVStack āļˆāļ°āđ€āļĨāļ·āđˆāļ­āļ™āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡āļ™āļĩāđ‰āļ­āļ­āļāđ„āļ› āļĨāļ”āļāļēāļĢāđƒāļŠāđ‰āļŦāļ™āđˆāļ§āļĒāļ„āļ§āļēāļĄāļˆāļģāđāļĨāļ°āđ€āļ§āļĨāļēāđƒāļ™āļāļēāļĢāđ€āļĢāļ™āđ€āļ”āļ­āļĢāđŒāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™āđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āļĄāļēāļ

LazyVStackComparison.swiftswift
import SwiftUI

// ❌ Problem: VStack instantiates all 10,000 views immediately
struct NonLazyListView: View {
    let items = (1...10000).map { "Item \($0)" }

    var body: some View {
        ScrollView {
            VStack {
                ForEach(items, id: \.self) { item in
                    // Each view is created at launch
                    ExpensiveRowView(title: item)
                }
            }
        }
    }
}

// ✅ Solution: LazyVStack creates views on demand
struct LazyListView: View {
    let items = (1...10000).map { "Item \($0)" }

    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach(items, id: \.self) { item in
                    // Only visible views are created
                    ExpensiveRowView(title: item)
                }
            }
        }
    }
}

āļ„āļ§āļēāļĄāđāļ•āļāļ•āđˆāļēāļ‡āļ‚āļ­āļ‡āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļˆāļ°āđ€āļŦāđ‡āļ™āđ„āļ”āđ‰āļŠāļąāļ”āđ€āļˆāļ™āđāļĄāđ‰āļāļąāļšāđ€āļžāļĩāļĒāļ‡āđ„āļĄāđˆāļāļĩāđˆāļĢāđ‰āļ­āļĒāļĢāļēāļĒāļāļēāļĢ āļ”āđ‰āļ§āļĒ 10,000 āļĢāļēāļĒāļāļēāļĢ VStack āļ­āļēāļˆāđƒāļŠāđ‰āđ€āļ§āļĨāļēāļŦāļĨāļēāļĒāļ§āļīāļ™āļēāļ—āļĩāđƒāļ™āļāļēāļĢāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™ āđƒāļ™āļ‚āļ“āļ°āļ—āļĩāđˆ LazyVStack āļĒāļąāļ‡āļ„āļ‡āļ•āļ­āļšāļŠāļ™āļ­āļ‡āļ—āļąāļ™āļ—āļĩ

āļāļēāļĢāļ§āļąāļ”āļœāļĨāļāļĢāļ°āļ—āļšāļ‚āļ­āļ‡ Lazy Loading

Instruments āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āļŠāļēāļĄāļēāļĢāļ–āļ§āļąāļ”āļāļēāļĢāđƒāļŠāđ‰āļŦāļ™āđˆāļ§āļĒāļ„āļ§āļēāļĄāļˆāļģāđāļĨāļ° CPU āđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āđāļĄāđˆāļ™āļĒāļģ āļ™āļĩāđˆāļ„āļ·āļ­āļ§āļīāļ§āļ—āļ”āļŠāļ­āļšāļ—āļĩāđˆāđāļŠāļ”āļ‡āļ„āļ§āļēāļĄāđāļ•āļāļ•āđˆāļēāļ‡:

PerformanceMeasurement.swiftswift
struct ExpensiveRowView: View {
    let title: String

    // Simulating expensive initialization
    init(title: String) {
        self.title = title
        // Log to visualize when the view is created
        print("Creating row: \(title)")
    }

    var body: some View {
        HStack {
            // Image with processing
            Circle()
                .fill(
                    LinearGradient(
                        colors: [.blue, .purple],
                        startPoint: .topLeading,
                        endPoint: .bottomTrailing
                    )
                )
                .frame(width: 50, height: 50)

            VStack(alignment: .leading) {
                Text(title)
                    .font(.headline)
                Text("Subtitle with computation")
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }

            Spacer()
        }
        .padding()
    }
}

āđ€āļĄāļ·āđˆāļ­āļĢāļąāļ™āļ”āđ‰āļ§āļĒ VStack āļĨāđ‡āļ­āļāļ—āļąāđ‰āļ‡āļŦāļĄāļ” 10,000 āļĢāļēāļĒāļāļēāļĢāļˆāļ°āļ›āļĢāļēāļāļāļ—āļąāļ™āļ—āļĩ āļ”āđ‰āļ§āļĒ LazyVStack āļĄāļĩāđ€āļžāļĩāļĒāļ‡āļĢāļēāļĒāļāļēāļĢāļ—āļĩāđˆāļĄāļ­āļ‡āđ€āļŦāđ‡āļ™āđ„āļ”āđ‰ (āļ›āļĢāļ°āļĄāļēāļ“ 15-20 āļ‚āļķāđ‰āļ™āļ­āļĒāļđāđˆāļāļąāļšāļ‚āļ™āļēāļ”āļŦāļ™āđ‰āļēāļˆāļ­) āļ—āļĩāđˆāļ–āļđāļāļĨāđ‡āļ­āļāđƒāļ™āļ•āļ­āļ™āđāļĢāļ āđ‚āļ”āļĒāļĄāļĩāļĢāļēāļĒāļāļēāļĢāđ€āļžāļīāđˆāļĄāđ€āļ•āļīāļĄāļ›āļĢāļēāļāļāļ‚āļķāđ‰āļ™āđ€āļĄāļ·āđˆāļ­āđ€āļĨāļ·āđˆāļ­āļ™

āļžāļĪāļ•āļīāļāļĢāļĢāļĄāļāļēāļĢāļ„āļ‡āļ­āļĒāļđāđˆ

LazyVStack āđ€āļāđ‡āļšāļ§āļīāļ§āļ—āļĩāđˆāļŠāļĢāđ‰āļēāļ‡āđ„āļ§āđ‰āđƒāļ™āļŦāļ™āđˆāļ§āļĒāļ„āļ§āļēāļĄāļˆāļģāļŦāļĨāļąāļ‡āļˆāļēāļāļ—āļĩāđˆāļ›āļĢāļēāļāļ āļ•āđˆāļēāļ‡āļˆāļēāļ List āļ—āļĩāđˆāļĢāļĩāđ„āļ‹āđ€āļ„āļīāļĨāđ€āļ‹āļĨāļĨāđŒāļ­āļĒāđˆāļēāļ‡āđāļ­āļ„āļ—āļĩāļŸ āļ§āļīāļ§āđƒāļ™ LazyVStack āļˆāļ°āļ„āļ‡āļ­āļĒāļđāđˆāļˆāļ™āļāļ§āđˆāļēāļŠāđˆāļ§āļ™āļ›āļĢāļ°āļāļ­āļšāļŦāļĨāļąāļāļˆāļ°āļ–āļđāļāļ—āļģāļĨāļēāļĒ

āļ„āļ§āļēāļĄāļŠāļģāļ„āļąāļāļ‚āļ­āļ‡āļ•āļąāļ§āļĢāļ°āļšāļļāļ—āļĩāđˆāđ€āļŠāļ–āļĩāļĒāļĢ

āļ•āļąāļ§āļĢāļ°āļšāļļāđ€āļ›āđ‡āļ™āļāļĨāđ„āļāļŦāļĨāļąāļāļ‚āļ­āļ‡āļāļēāļĢāļ­āļąāļ›āđ€āļ”āļ•āļĢāļēāļĒāļāļēāļĢ SwiftUI āļ•āļąāļ§āļĢāļ°āļšāļļāļ—āļĩāđˆāđ„āļĄāđˆāđ€āļŠāļ–āļĩāļĒāļĢāļ—āļģāđƒāļŦāđ‰āđ€āļāļīāļ”āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡āļ§āļīāļ§āđƒāļŦāļĄāđˆāļ—āļĩāđˆāđ„āļĄāđˆāļˆāļģāđ€āļ›āđ‡āļ™āđāļĨāļ°āļ­āļēāļˆāļāļĢāļ°āļ•āļļāđ‰āļ™āļšāļąāđŠāļāļ—āļēāļ‡āļŠāļēāļĒāļ•āļē āđ€āļŠāđˆāļ™ āđāļ­āļ™āļīāđ€āļĄāļŠāļąāļ™āļ—āļĩāđˆāļœāļīāļ”āļžāļĨāļēāļ”āļŦāļĢāļ·āļ­āļāļēāļĢāļŠāļđāļāđ€āļŠāļĩāļĒāļ•āļģāđāļŦāļ™āđˆāļ‡āļāļēāļĢāđ€āļĨāļ·āđˆāļ­āļ™

StableIdentifiers.swiftswift
// ❌ Problem: using index as identifier
struct UnstableIdentifierView: View {
    @State private var items = ["A", "B", "C", "D"]

    var body: some View {
        List {
            // Index changes if an element is deleted
            ForEach(items.indices, id: \.self) { index in
                Text(items[index])
            }
        }
    }
}

// ❌ Problem: using UUID() in ForEach
struct RegeneratedIdentifierView: View {
    let items = ["A", "B", "C", "D"]

    var body: some View {
        List {
            // UUID() generates a new ID on each render
            ForEach(items, id: \.self) { item in
                // Subtle issue if items contain duplicates
                Text(item)
            }
        }
    }
}

// ✅ Solution: model with stable identifier
struct Item: Identifiable {
    let id: UUID  // Created once
    var name: String

    init(name: String) {
        self.id = UUID()
        self.name = name
    }
}

struct StableIdentifierView: View {
    @State private var items = [
        Item(name: "A"),
        Item(name: "B"),
        Item(name: "C"),
        Item(name: "D")
    ]

    var body: some View {
        List {
            // id is stable for the item's lifetime
            ForEach(items) { item in
                Text(item.name)
            }
        }
    }
}

āļāļēāļĢāđƒāļŠāđ‰āļ•āļąāļ§āļĢāļ°āļšāļļāļ—āļĩāđˆāđ„āļĄāđˆāļ‹āđ‰āļģāļāļąāļ™āđāļĨāļ°āļ„āļ‡āļ—āļ™āļŠāđˆāļ§āļĒāđƒāļŦāđ‰ SwiftUI āļŠāļēāļĄāļēāļĢāļ–āđāļĒāļāđāļĒāļ°āļ­āļ‡āļ„āđŒāļ›āļĢāļ°āļāļ­āļšāđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āļ–āļđāļāļ•āđ‰āļ­āļ‡āļĢāļ°āļŦāļ§āđˆāļēāļ‡āļāļēāļĢāļ­āļąāļ›āđ€āļ”āļ• āđāļ­āļ™āļīāđ€āļĄāļŠāļąāļ™ āđāļĨāļ°āļāļēāļĢāđ€āļ›āļĢāļĩāļĒāļšāđ€āļ—āļĩāļĒāļš

āļāļēāļĢāļ›āļĢāļąāļšāđāļ•āđˆāļ‡āđ€āļ‹āļĨāļĨāđŒāļ”āđ‰āļ§āļĒ Equatable

SwiftUI āđ€āļ›āļĢāļĩāļĒāļšāđ€āļ—āļĩāļĒāļšāļ§āļīāļ§āđ€āļžāļ·āđˆāļ­āļžāļīāļˆāļēāļĢāļ“āļēāļ§āđˆāļēāļˆāļģāđ€āļ›āđ‡āļ™āļ•āđ‰āļ­āļ‡āđ€āļĢāļ™āđ€āļ”āļ­āļĢāđŒāđƒāļŦāļĄāđˆāļŦāļĢāļ·āļ­āđ„āļĄāđˆ āđ‚āļ”āļĒāļ„āđˆāļēāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™ āļāļēāļĢāđ€āļ›āļĢāļĩāļĒāļšāđ€āļ—āļĩāļĒāļšāļ™āļĩāđ‰āđƒāļŠāđ‰ reflection āļ‹āļķāđˆāļ‡āļ­āļēāļˆāļĄāļĩāļ„āđˆāļēāđƒāļŠāđ‰āļˆāđˆāļēāļĒāļŠāļđāļ‡ āļāļēāļĢāđƒāļŠāđ‰ Equatable āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āļŠāļēāļĄāļēāļĢāļ–āđ€āļ›āļĢāļĩāļĒāļšāđ€āļ—āļĩāļĒāļšāđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āļĄāļĩāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāđāļĨāļ°āļŠāļąāļ”āđ€āļˆāļ™

EquatableOptimization.swiftswift
// Data model
struct Contact: Identifiable, Equatable {
    let id: UUID
    var name: String
    var email: String
    var avatarURL: URL?
    var lastActivity: Date

    // Custom comparison: ignore lastActivity
    // if other properties are identical
    static func == (lhs: Contact, rhs: Contact) -> Bool {
        lhs.id == rhs.id &&
        lhs.name == rhs.name &&
        lhs.email == rhs.email &&
        lhs.avatarURL == rhs.avatarURL
        // lastActivity intentionally excluded
    }
}

// Optimized cell view
struct ContactRow: View, Equatable {
    let contact: Contact

    // Explicit comparison to avoid unnecessary re-renders
    static func == (lhs: ContactRow, rhs: ContactRow) -> Bool {
        lhs.contact == rhs.contact
    }

    var body: some View {
        HStack(spacing: 12) {
            // Async avatar
            AsyncImage(url: contact.avatarURL) { phase in
                switch phase {
                case .success(let image):
                    image
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                case .failure:
                    Image(systemName: "person.circle.fill")
                        .foregroundStyle(.gray)
                default:
                    ProgressView()
                }
            }
            .frame(width: 44, height: 44)
            .clipShape(Circle())

            // Contact information
            VStack(alignment: .leading, spacing: 2) {
                Text(contact.name)
                    .font(.body.weight(.medium))

                Text(contact.email)
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }

            Spacer()
        }
        .padding(.vertical, 4)
    }
}

// List using EquatableView
struct ContactListView: View {
    let contacts: [Contact]

    var body: some View {
        List {
            ForEach(contacts) { contact in
                // EquatableView prevents re-renders if contact unchanged
                EquatableView(content: ContactRow(contact: contact))
            }
        }
    }
}

āļāļēāļĢāļ›āļĢāļąāļšāđāļ•āđˆāļ‡āļ™āļĩāđ‰āļĨāļ”āļ āļēāļĢāļ° CPU āļ­āļĒāđˆāļēāļ‡āļĄāļĩāļ™āļąāļĒāļŠāļģāļ„āļąāļāđƒāļ™āļĢāļ°āļŦāļ§āđˆāļēāļ‡āļāļēāļĢāđ€āļĨāļ·āđˆāļ­āļ™āđ€āļĢāđ‡āļ§ āđ‚āļ”āļĒāđ€āļ‰āļžāļēāļ°āļāļąāļšāđ€āļ‹āļĨāļĨāđŒāļ—āļĩāđˆāļĄāļĩāļāļēāļĢāļ„āļģāļ™āļ§āļ“āļŦāļĢāļ·āļ­āļĢāļđāļ›āļ āļēāļž

āļžāļĢāđ‰āļ­āļĄāļ—āļĩāđˆāļˆāļ°āļžāļīāļŠāļīāļ•āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ iOS āđāļĨāđ‰āļ§āļŦāļĢāļ·āļ­āļĒāļąāļ‡āļ„āļĢāļąāļš?

āļāļķāļāļāļ™āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āđāļšāļšāđ‚āļ•āđ‰āļ•āļ­āļš, flashcards āđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

āļāļēāļĢāļˆāļąāļ”āļāļēāļĢāļāļēāļĢāđ‚āļŦāļĨāļ”āļĢāļđāļ›āļ āļēāļžāđāļšāļšāļ­āļ°āļ‹āļīāļ‡āđ‚āļ„āļĢāļ™āļąāļŠ

āļĢāļđāļ›āļ āļēāļžāļĄāļąāļāļˆāļ°āļāļĨāļēāļĒāđ€āļ›āđ‡āļ™āļˆāļļāļ”āļ„āļ­āļ‚āļ§āļ”āļ”āđ‰āļēāļ™āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāđƒāļ™āļĢāļēāļĒāļāļēāļĢ āļāļēāļĢāļˆāļąāļ”āļāļēāļĢāļ—āļĩāđˆāđ„āļĄāđˆāļ–āļđāļāļ•āđ‰āļ­āļ‡āļ—āļģāđƒāļŦāđ‰āđ€āļāļīāļ”āļāļēāļĢāļāļĢāļ°āļ•āļļāļāđƒāļ™āļāļēāļĢāđ€āļĨāļ·āđˆāļ­āļ™āđāļĨāļ°āļāļēāļĢāđƒāļŠāđ‰āļŦāļ™āđˆāļ§āļĒāļ„āļ§āļēāļĄāļˆāļģāļĄāļēāļāđ€āļāļīāļ™āđ„āļ›

ImageLoadingOptimization.swiftswift
import SwiftUI

// Singleton image cache
actor ImageCache {
    static let shared = ImageCache()

    private var cache = NSCache<NSString, UIImage>()

    private init() {
        // Memory limit: 50 MB
        cache.totalCostLimit = 50 * 1024 * 1024
    }

    func image(for url: URL) -> UIImage? {
        cache.object(forKey: url.absoluteString as NSString)
    }

    func setImage(_ image: UIImage, for url: URL) {
        // Cost estimation: image bytes
        let cost = Int(image.size.width * image.size.height * 4)
        cache.setObject(image, forKey: url.absoluteString as NSString, cost: cost)
    }
}

// Optimized image view with caching
struct CachedAsyncImage: View {
    let url: URL?
    let size: CGSize

    @State private var image: UIImage?
    @State private var isLoading = false

    var body: some View {
        Group {
            if let image {
                Image(uiImage: image)
                    .resizable()
                    .aspectRatio(contentMode: .fill)
            } else if isLoading {
                Rectangle()
                    .fill(Color.gray.opacity(0.2))
                    .overlay(ProgressView())
            } else {
                Rectangle()
                    .fill(Color.gray.opacity(0.2))
            }
        }
        .frame(width: size.width, height: size.height)
        .clipped()
        .task(id: url) {
            await loadImage()
        }
    }

    private func loadImage() async {
        guard let url else { return }

        // Check cache
        if let cached = await ImageCache.shared.image(for: url) {
            self.image = cached
            return
        }

        isLoading = true
        defer { isLoading = false }

        // Download and resize
        do {
            let (data, _) = try await URLSession.shared.data(from: url)

            // Resize to save memory
            if let original = UIImage(data: data),
               let resized = await resizeImage(original, to: size) {
                await ImageCache.shared.setImage(resized, for: url)
                self.image = resized
            }
        } catch {
            // Handle error silently
        }
    }

    private func resizeImage(_ image: UIImage, to size: CGSize) async -> UIImage? {
        // Use screen scale
        let scale = await UIScreen.main.scale
        let targetSize = CGSize(
            width: size.width * scale,
            height: size.height * scale
        )

        return await withCheckedContinuation { continuation in
            DispatchQueue.global(qos: .userInitiated).async {
                let renderer = UIGraphicsImageRenderer(size: targetSize)
                let resized = renderer.image { _ in
                    image.draw(in: CGRect(origin: .zero, size: targetSize))
                }
                continuation.resume(returning: resized)
            }
        }
    }
}

āļāļēāļĢāđƒāļŠāđ‰āļ‡āļēāļ™āļ™āļĩāđ‰āļœāļŠāļĄāļœāļŠāļēāļ™āļāļēāļĢāđāļ„āļŠāļŦāļ™āđˆāļ§āļĒāļ„āļ§āļēāļĄāļˆāļģ āļāļēāļĢāļ›āļĢāļąāļšāļ‚āļ™āļēāļ”āļĨāđˆāļ§āļ‡āļŦāļ™āđ‰āļē āđāļĨāļ°āļāļēāļĢāđ‚āļŦāļĨāļ”āđāļšāļšāļ­āļ°āļ‹āļīāļ‡āđ‚āļ„āļĢāļ™āļąāļŠāđ€āļžāļ·āđˆāļ­āļ›āļĢāļ°āļŠāļšāļāļēāļĢāļ“āđŒāļāļēāļĢāđ€āļĨāļ·āđˆāļ­āļ™āļ—āļĩāđˆāļĨāļ·āđˆāļ™āđ„āļŦāļĨ

Prefetching āļ­āļąāļˆāļ‰āļĢāļīāļĒāļ°āđ€āļžāļ·āđˆāļ­āļāļēāļĢāļ„āļēāļ”āļāļēāļĢāļ“āđŒ

āļŠāļģāļŦāļĢāļąāļšāļĢāļēāļĒāļāļēāļĢāļ—āļĩāđˆāļĒāļēāļ§āļĄāļēāļ prefetching āļˆāļ°āđ‚āļŦāļĨāļ”āļĢāļđāļ›āļ āļēāļžāļāđˆāļ­āļ™āļ—āļĩāđˆāļˆāļ°āļ›āļĢāļēāļāļ:

ImagePrefetching.swiftswift
// Prefetching coordinator
@Observable
final class ImagePrefetcher {
    private var prefetchTasks: [URL: Task<Void, Never>] = [:]
    private let prefetchDistance = 10  // Number of items ahead

    func prefetchImages(for items: [Contact], visibleRange: Range<Int>) {
        // Calculate prefetch range
        let prefetchStart = max(0, visibleRange.lowerBound - prefetchDistance)
        let prefetchEnd = min(items.count, visibleRange.upperBound + prefetchDistance)

        // Launch prefetch for items in range
        for index in prefetchStart..<prefetchEnd {
            guard let url = items[index].avatarURL else { continue }

            // Avoid duplicates
            guard prefetchTasks[url] == nil else { continue }

            prefetchTasks[url] = Task {
                // Check if already cached
                if await ImageCache.shared.image(for: url) != nil {
                    return
                }

                // Prefetch
                do {
                    let (data, _) = try await URLSession.shared.data(from: url)
                    if let image = UIImage(data: data) {
                        await ImageCache.shared.setImage(image, for: url)
                    }
                } catch {
                    // Ignore prefetch errors
                }
            }
        }

        // Cancel out-of-range prefetches
        cancelOutOfRangePrefetches(validRange: prefetchStart..<prefetchEnd, items: items)
    }

    private func cancelOutOfRangePrefetches(validRange: Range<Int>, items: [Contact]) {
        let validURLs = Set(
            items[validRange].compactMap { $0.avatarURL }
        )

        for (url, task) in prefetchTasks {
            if !validURLs.contains(url) {
                task.cancel()
                prefetchTasks.removeValue(forKey: url)
            }
        }
    }
}

āļāļēāļĢāđ€āļĨāļ·āļ­āļāļĢāļ°āļŦāļ§āđˆāļēāļ‡ List āđāļĨāļ° LazyVStack

āļāļēāļĢāđ€āļĨāļ·āļ­āļāļĢāļ°āļŦāļ§āđˆāļēāļ‡ List āđāļĨāļ° LazyVStack āļ‚āļķāđ‰āļ™āļ­āļĒāļđāđˆāļāļąāļšāļāļĢāļ“āļĩāļāļēāļĢāđƒāļŠāđ‰āļ‡āļēāļ™ āđāļ•āđˆāļĨāļ°āļŠāđˆāļ§āļ™āļ›āļĢāļ°āļāļ­āļšāļĄāļĩāļ‚āđ‰āļ­āđ„āļ”āđ‰āđ€āļ›āļĢāļĩāļĒāļšāđ€āļ‰āļžāļēāļ°āļ—āļĩāđˆāļ„āļ§āļĢāļ—āļĢāļēāļš

ListVsLazyVStack.swiftswift
// ✅ List: ideal for interactive content
// - Automatic cell recycling
// - Native swipe actions support
// - Built-in separators and styles
struct ContactsWithSwipeActions: View {
    @State private var contacts: [Contact] = []

    var body: some View {
        List {
            ForEach(contacts) { contact in
                ContactRow(contact: contact)
                    .swipeActions(edge: .trailing) {
                        Button(role: .destructive) {
                            deleteContact(contact)
                        } label: {
                            Label("Delete", systemImage: "trash")
                        }
                    }
                    .swipeActions(edge: .leading) {
                        Button {
                            favoriteContact(contact)
                        } label: {
                            Label("Favorite", systemImage: "star")
                        }
                        .tint(.yellow)
                    }
            }
        }
        .listStyle(.plain)
    }

    private func deleteContact(_ contact: Contact) {
        contacts.removeAll { $0.id == contact.id }
    }

    private func favoriteContact(_ contact: Contact) {
        // Favorite logic
    }
}

// ✅ LazyVStack: ideal for custom layouts
// - Full control over spacing and padding
// - No imposed styles
// - Better performance for simple display
struct CustomFeedView: View {
    let posts: [Post]

    var body: some View {
        ScrollView {
            LazyVStack(spacing: 16) {
                ForEach(posts) { post in
                    PostCard(post: post)
                }
            }
            .padding(.horizontal)
        }
    }
}

// Post model for example
struct Post: Identifiable {
    let id: UUID
    let author: String
    let content: String
    let imageURL: URL?
}

struct PostCard: View {
    let post: Post

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            // Header
            HStack {
                Circle()
                    .fill(Color.blue)
                    .frame(width: 40, height: 40)

                Text(post.author)
                    .font(.headline)

                Spacer()
            }

            // Content
            Text(post.content)

            // Optional image
            if let imageURL = post.imageURL {
                CachedAsyncImage(url: imageURL, size: CGSize(width: 300, height: 200))
                    .cornerRadius(12)
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(16)
        .shadow(color: .black.opacity(0.1), radius: 4, y: 2)
    }
}
āļāļēāļĢāļĢāļĩāđ„āļ‹āđ€āļ„āļīāļĨāđ€āļ‹āļĨāļĨāđŒ

List āļĢāļĩāđ„āļ‹āđ€āļ„āļīāļĨāđ€āļ‹āļĨāļĨāđŒāļ­āļĒāđˆāļēāļ‡āđāļ­āļ„āļ—āļĩāļŸ āļ‹āļķāđˆāļ‡āļ­āļēāļˆāļ—āļģāđƒāļŦāđ‰āđ€āļāļīāļ”āļ›āļąāļāļŦāļēāļāļąāļš state āļ āļēāļĒāđƒāļ™ (@State) āļ„āđˆāļē @State āđƒāļ™āđ€āļ‹āļĨāļĨāđŒāļ‚āļ­āļ‡ List āļ­āļēāļˆāļ–āļđāļāđƒāļŠāđ‰āļ‹āđ‰āļģāđ‚āļ”āļĒāđ„āļĄāđˆāļ„āļēāļ”āļ„āļīāļ” āļ„āļ§āļĢāđ€āļāđ‡āļš state āđ„āļ§āđ‰āđƒāļ™āđ‚āļĄāđ€āļ”āļĨāļ‚āđ‰āļ­āļĄāļđāļĨāļŦāļĢāļ·āļ­āđƒāļ™ ViewModel

āđ€āļ‹āļāļŠāļąāļ™āđāļĨāļ°āļŠāđˆāļ§āļ™āļŦāļąāļ§āļ—āļĩāđˆāļ›āļĢāļąāļšāđāļ•āđˆāļ‡āđāļĨāđ‰āļ§

āļāļēāļĢāļˆāļąāļ”āđ€āļ™āļ·āđ‰āļ­āļŦāļēāđ€āļ›āđ‡āļ™āđ€āļ‹āļāļŠāļąāļ™āļŠāđˆāļ§āļĒāļ›āļĢāļąāļšāļ›āļĢāļļāļ‡āļ„āļ§āļēāļĄāļŠāļēāļĄāļēāļĢāļ–āđƒāļ™āļāļēāļĢāļ­āđˆāļēāļ™āđāļ•āđˆāļ­āļēāļˆāļŠāđˆāļ‡āļœāļĨāļāļĢāļ°āļ—āļšāļ•āđˆāļ­āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļŦāļēāļāđƒāļŠāđ‰āļ‡āļēāļ™āđ„āļĄāđˆāļ”āļĩ āļŠāđˆāļ§āļ™āļŦāļąāļ§āļ—āļĩāđˆāļ•āļĢāļķāļ‡āđāļĨāļ°āļāļēāļĢāļˆāļąāļ”āļāļēāļĢāđ€āļ‹āļāļŠāļąāļ™āļ•āđ‰āļ­āļ‡āļāļēāļĢāļ„āļ§āļēāļĄāđƒāļŠāđˆāđƒāļˆāđ€āļ›āđ‡āļ™āļžāļīāđ€āļĻāļĐ

OptimizedSections.swiftswift
// Grouped data model
struct GroupedContacts {
    let letter: String
    let contacts: [Contact]
}

// View with optimized sections
struct SectionedContactList: View {
    let groupedContacts: [GroupedContacts]

    var body: some View {
        ScrollView {
            LazyVStack(spacing: 0, pinnedViews: [.sectionHeaders]) {
                ForEach(groupedContacts, id: \.letter) { group in
                    Section {
                        // Section content
                        ForEach(group.contacts) { contact in
                            ContactRow(contact: contact)
                                .padding(.horizontal)
                                .padding(.vertical, 8)

                            // Custom separator
                            if contact.id != group.contacts.last?.id {
                                Divider()
                                    .padding(.leading, 68)
                            }
                        }
                    } header: {
                        // Optimized pinned header
                        SectionHeader(title: group.letter)
                    }
                }
            }
        }
    }
}

// Lightweight header for performance
struct SectionHeader: View {
    let title: String

    var body: some View {
        Text(title)
            .font(.headline)
            .foregroundStyle(.secondary)
            .frame(maxWidth: .infinity, alignment: .leading)
            .padding(.horizontal)
            .padding(.vertical, 8)
            .background(.ultraThinMaterial)
    }
}

// Optimized grouping function
extension Array where Element == Contact {
    func groupedByFirstLetter() -> [GroupedContacts] {
        // Dictionary for O(n) grouping
        var groups: [String: [Contact]] = [:]

        for contact in self {
            let letter = String(contact.name.prefix(1)).uppercased()
            groups[letter, default: []].append(contact)
        }

        // Sort groups alphabetically
        return groups
            .map { GroupedContacts(letter: $0.key, contacts: $0.value) }
            .sorted { $0.letter < $1.letter }
    }
}

āļŠāđˆāļ§āļ™āļŦāļąāļ§āļ—āļĩāđˆāļ•āļĢāļķāļ‡ (pinnedViews: [.sectionHeaders]) āļĒāļąāļ‡āļ„āļ‡āļĄāļ­āļ‡āđ€āļŦāđ‡āļ™āđ„āļ”āđ‰āļĢāļ°āļŦāļ§āđˆāļēāļ‡āļāļēāļĢāđ€āļĨāļ·āđˆāļ­āļ™ āļ›āļĢāļąāļšāļ›āļĢāļļāļ‡āļāļēāļĢāļ™āļģāļ—āļēāļ‡āđƒāļ™āļĢāļēāļĒāļāļēāļĢāļ—āļĩāđˆāļĒāļēāļ§

āļāļēāļĢāđāļšāđˆāļ‡āļŦāļ™āđ‰āļēāđāļĨāļ°āļāļēāļĢāđ€āļĨāļ·āđˆāļ­āļ™āđāļšāļšāđ„āļĄāđˆāļˆāļģāļāļąāļ”

āļŠāļģāļŦāļĢāļąāļšāļŠāļļāļ”āļ‚āđ‰āļ­āļĄāļđāļĨāļ‚āļ™āļēāļ”āđƒāļŦāļāđˆ āļāļēāļĢāđāļšāđˆāļ‡āļŦāļ™āđ‰āļēāļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļāļēāļĢāđ‚āļŦāļĨāļ”āļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļąāđ‰āļ‡āļŦāļĄāļ”āļĨāļ‡āđƒāļ™āļŦāļ™āđˆāļ§āļĒāļ„āļ§āļēāļĄāļˆāļģ āļāļēāļĢāđƒāļŠāđ‰āļ‡āļēāļ™āļ•āđ‰āļ­āļ‡āđ‚āļ›āļĢāđˆāļ‡āđƒāļŠāļŠāļģāļŦāļĢāļąāļšāļœāļđāđ‰āđƒāļŠāđ‰

InfiniteScrolling.swiftswift
// ViewModel handling pagination
@Observable
final class PaginatedListViewModel {
    private(set) var items: [Contact] = []
    private(set) var isLoading = false
    private(set) var hasMorePages = true

    private var currentPage = 0
    private let pageSize = 20
    private let dataService: ContactDataService

    init(dataService: ContactDataService) {
        self.dataService = dataService
    }

    func loadInitialData() async {
        guard items.isEmpty else { return }
        await loadNextPage()
    }

    func loadMoreIfNeeded(currentItem: Contact) async {
        // Trigger loading when approaching the end
        guard let index = items.firstIndex(where: { $0.id == currentItem.id }) else {
            return
        }

        // Load 5 items before the end
        let thresholdIndex = items.count - 5

        if index >= thresholdIndex {
            await loadNextPage()
        }
    }

    private func loadNextPage() async {
        guard !isLoading, hasMorePages else { return }

        isLoading = true
        defer { isLoading = false }

        do {
            let newItems = try await dataService.fetchContacts(
                page: currentPage,
                limit: pageSize
            )

            items.append(contentsOf: newItems)
            currentPage += 1
            hasMorePages = newItems.count == pageSize
        } catch {
            // Handle error
        }
    }
}

// View with infinite scroll
struct InfiniteContactList: View {
    @State private var viewModel: PaginatedListViewModel

    init(dataService: ContactDataService) {
        _viewModel = State(initialValue: PaginatedListViewModel(dataService: dataService))
    }

    var body: some View {
        List {
            ForEach(viewModel.items) { contact in
                ContactRow(contact: contact)
                    .task {
                        // Check if more loading needed
                        await viewModel.loadMoreIfNeeded(currentItem: contact)
                    }
            }

            // Loading indicator at end of list
            if viewModel.isLoading {
                HStack {
                    Spacer()
                    ProgressView()
                    Spacer()
                }
                .padding()
            }
        }
        .task {
            await viewModel.loadInitialData()
        }
    }
}

// Protocol for data service
protocol ContactDataService {
    func fetchContacts(page: Int, limit: Int) async throws -> [Contact]
}

āļĢāļđāļ›āđāļšāļšāļ™āļĩāđ‰āļĢāļąāļšāļ›āļĢāļ°āļāļąāļ™āļāļēāļĢāđ‚āļŦāļĨāļ”āļ—āļĩāđˆāļĨāļ·āđˆāļ™āđ„āļŦāļĨāđ‚āļ”āļĒāđ„āļĄāđˆāļ›āļīāļ”āļāļąāđ‰āļ™āļ­āļīāļ™āđ€āļ—āļ­āļĢāđŒāđ€āļŸāļ‹āđāļĨāļ°āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āļŠāļēāļĄāļēāļĢāļ–āļˆāļąāļ”āļāļēāļĢāļŦāļ™āđˆāļ§āļĒāļ„āļ§āļēāļĄāļˆāļģāđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āļĄāļĩāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž

āļžāļĢāđ‰āļ­āļĄāļ—āļĩāđˆāļˆāļ°āļžāļīāļŠāļīāļ•āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ iOS āđāļĨāđ‰āļ§āļŦāļĢāļ·āļ­āļĒāļąāļ‡āļ„āļĢāļąāļš?

āļāļķāļāļāļ™āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āđāļšāļšāđ‚āļ•āđ‰āļ•āļ­āļš, flashcards āđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

āļāļēāļĢāļ—āļģ Profiling āļ”āđ‰āļ§āļĒ Instruments

āļāļēāļĢāļĢāļ°āļšāļļāļ›āļąāļāļŦāļēāļ”āđ‰āļēāļ™āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļ•āđ‰āļ­āļ‡āļāļēāļĢāđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­āļ§āļąāļ”āļœāļĨāļ—āļĩāđˆāđāļĄāđˆāļ™āļĒāļģ Instruments āļĄāļĩāđ€āļ—āļĄāđ€āļžāļĨāļ•āļŦāļĨāļēāļĒāđāļšāļšāļ—āļĩāđˆāđ€āļŦāļĄāļēāļ°āļŠāļģāļŦāļĢāļąāļš SwiftUI

ProfilingHelpers.swiftswift
// Measurement points for debugging
struct PerformanceMonitor {
    // Measure view creation time
    static func measureViewCreation<T: View>(
        _ name: String,
        @ViewBuilder content: () -> T
    ) -> T {
        let start = CFAbsoluteTimeGetCurrent()
        let view = content()
        let elapsed = CFAbsoluteTimeGetCurrent() - start

        #if DEBUG
        if elapsed > 0.016 {  // More than 16ms = frame drop
            print("⚠ïļ [\(name)] View creation took \(elapsed * 1000)ms")
        }
        #endif

        return view
    }
}

// Extension to trace renders
extension View {
    func debugRender(_ label: String) -> some View {
        #if DEBUG
        let _ = Self._printChanges()
        print("🔄 Rendering: \(label)")
        #endif
        return self
    }

    func measureRender(_ label: String) -> some View {
        modifier(RenderMeasureModifier(label: label))
    }
}

struct RenderMeasureModifier: ViewModifier {
    let label: String
    @State private var renderCount = 0

    func body(content: Content) -> some View {
        content
            .onAppear {
                renderCount += 1
                #if DEBUG
                print("📊 [\(label)] Render count: \(renderCount)")
                #endif
            }
    }
}

āļĢāļēāļĒāļāļēāļĢāļ•āļĢāļ§āļˆāļŠāļ­āļšāļāļēāļĢāļ›āļĢāļąāļšāđāļ•āđˆāļ‡āļ”āđ‰āļ§āļĒ Instruments

āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ—āļģ profiling āļĢāļēāļĒāļāļēāļĢ SwiftUI āļ—āļĩāđˆāļĄāļĩāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž:

  1. Time Profiler: āļĢāļ°āļšāļļāļŸāļąāļ‡āļāđŒāļŠāļąāļ™āļ—āļĩāđˆāđƒāļŠāđ‰ CPU āļĄāļēāļāļ—āļĩāđˆāļŠāļļāļ”
  2. Allocations: āļ•āļĢāļ§āļˆāļŠāļ­āļšāļāļēāļĢāđ€āļ•āļīāļšāđ‚āļ•āļ‚āļ­āļ‡āļŦāļ™āđˆāļ§āļĒāļ„āļ§āļēāļĄāļˆāļģāļĢāļ°āļŦāļ§āđˆāļēāļ‡āļāļēāļĢāđ€āļĨāļ·āđˆāļ­āļ™
  3. SwiftUI Instrument: āđāļŠāļ”āļ‡āļ āļēāļžāļāļēāļĢāļ›āļĢāļ°āđ€āļĄāļīāļ™ body
  4. Core Animation: āļ•āļĢāļ§āļˆāļˆāļąāļšāļāļēāļĢāļĨāļ”āļĨāļ‡āļ‚āļ­āļ‡āđ€āļŸāļĢāļĄ
InstrumentsExample.swiftswift
// Instrumented view for profiling
struct ProfiledContactList: View {
    let contacts: [Contact]

    var body: some View {
        let _ = Self._printChanges()  // Shows changes triggering re-render

        List {
            ForEach(contacts) { contact in
                ContactRow(contact: contact)
                    .measureRender("ContactRow-\(contact.id)")
            }
        }
    }
}
Self._printChanges()

API debugging āļ‚āļ­āļ‡ SwiftUI āļ™āļĩāđ‰āļˆāļ°āļžāļīāļĄāļžāđŒāđ„āļ›āļĒāļąāļ‡āļ„āļ­āļ™āđ‚āļ‹āļĨāļ§āđˆāļēāļĄāļĩāļ„āļļāļ“āļŠāļĄāļšāļąāļ•āļīāđƒāļ”āļ—āļĩāđˆāđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡āđāļĨāļ°āļāļĢāļ°āļ•āļļāđ‰āļ™āļāļēāļĢāļ›āļĢāļ°āđ€āļĄāļīāļ™ body āđƒāļŦāļĄāđˆ āļˆāļģāđ€āļ›āđ‡āļ™āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļĢāļ°āļšāļļāļāļēāļĢāđ€āļĢāļ™āđ€āļ”āļ­āļĢāđŒāđƒāļŦāļĄāđˆāļ—āļĩāđˆāđ„āļĄāđˆāļˆāļģāđ€āļ›āđ‡āļ™

āļāļēāļĢāļ›āļĢāļąāļšāđāļ•āđˆāļ‡āļ‚āļąāđ‰āļ™āļŠāļđāļ‡āļ”āđ‰āļ§āļĒ drawingGroup

āļŠāļģāļŦāļĢāļąāļšāļ§āļīāļ§āļ—āļĩāđˆāļ‹āļąāļšāļ‹āđ‰āļ­āļ™āļ‹āļķāđˆāļ‡āļĄāļĩāđ€āļ­āļŸāđ€āļŸāļāļ•āđŒāļ āļēāļžāļŦāļĨāļēāļĒāļ­āļĒāđˆāļēāļ‡ drawingGroup() āļŠāļēāļĄāļēāļĢāļ–āļ›āļĢāļąāļšāļ›āļĢāļļāļ‡āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļ­āļĒāđˆāļēāļ‡āļĄāļĩāļ™āļąāļĒāļŠāļģāļ„āļąāļāđ‚āļ”āļĒāļāļēāļĢāđāļĢāļŠāđ€āļ•āļ­āļĢāđŒāđ„āļĢāļ‹āđŒāļ§āļīāļ§āđ€āļ›āđ‡āļ™āđ€āļĨāđ€āļĒāļ­āļĢāđŒ Metal

DrawingGroupOptimization.swiftswift
// Cell with complex visual effects
struct ComplexVisualRow: View {
    let item: Item

    var body: some View {
        HStack(spacing: 16) {
            // Circle with gradient and shadow
            Circle()
                .fill(
                    RadialGradient(
                        colors: [.blue, .purple, .pink],
                        center: .center,
                        startRadius: 0,
                        endRadius: 25
                    )
                )
                .frame(width: 50, height: 50)
                .shadow(color: .purple.opacity(0.5), radius: 8, y: 4)

            VStack(alignment: .leading, spacing: 4) {
                Text(item.name)
                    .font(.headline)

                // Progress bar with gradient
                GeometryReader { geometry in
                    Capsule()
                        .fill(Color.gray.opacity(0.2))
                        .overlay(alignment: .leading) {
                            Capsule()
                                .fill(
                                    LinearGradient(
                                        colors: [.green, .yellow, .orange],
                                        startPoint: .leading,
                                        endPoint: .trailing
                                    )
                                )
                                .frame(width: geometry.size.width * item.progress)
                        }
                }
                .frame(height: 8)
            }
        }
        .padding()
        // Rasterization for performance
        .drawingGroup()
    }
}

// List using optimized cells
struct OptimizedComplexList: View {
    let items: [Item]

    var body: some View {
        ScrollView {
            LazyVStack(spacing: 8) {
                ForEach(items) { item in
                    ComplexVisualRow(item: item)
                }
            }
            .padding()
        }
    }
}

struct Item: Identifiable {
    let id: UUID
    let name: String
    let progress: Double
}

drawingGroup() āļĄāļĩāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāđ€āļ›āđ‡āļ™āļžāļīāđ€āļĻāļĐāļŠāļģāļŦāļĢāļąāļšāļ§āļīāļ§āļ—āļĩāđˆāļœāļŠāļĄāļœāļŠāļēāļ™āđ€āļāļĢāđ€āļ”āļĩāļĒāļ™āļ•āđŒ āđ€āļ‡āļē āđāļĨāļ°āđ€āļ­āļŸāđ€āļŸāļāļ•āđŒāđ€āļšāļĨāļ­

āļšāļ—āļŠāļĢāļļāļ›

āļāļēāļĢāļ›āļĢāļąāļšāđāļ•āđˆāļ‡āļĢāļēāļĒāļāļēāļĢ SwiftUI āļ‚āļķāđ‰āļ™āļ­āļĒāļđāđˆāļāļąāļšāļ„āļ§āļēāļĄāđ€āļ‚āđ‰āļēāđƒāļˆāļ­āļĒāđˆāļēāļ‡āļĨāļķāļāļ‹āļķāđ‰āļ‡āđ€āļāļĩāđˆāļĒāļ§āļāļąāļšāļāļĨāđ„āļ lazy loading āļāļēāļĢāļĢāļĩāđ„āļ‹āđ€āļ„āļīāļĨ āđāļĨāļ°āļāļēāļĢāđ€āļ›āļĢāļĩāļĒāļšāđ€āļ—āļĩāļĒāļšāļ§āļīāļ§ āđ€āļ—āļ„āļ™āļīāļ„āļ—āļĩāđˆāļ™āļģāđ€āļŠāļ™āļ­āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āļŠāļēāļĄāļēāļĢāļ–āļŠāļĢāđ‰āļēāļ‡āļ­āļīāļ™āđ€āļ—āļ­āļĢāđŒāđ€āļŸāļ‹āļ—āļĩāđˆāļŠāļēāļĄāļēāļĢāļ–āļˆāļąāļ”āļāļēāļĢāļāļąāļšāļ­āļ‡āļ„āđŒāļ›āļĢāļ°āļāļ­āļšāļŦāļĨāļēāļĒāļžāļąāļ™āļĢāļēāļĒāļāļēāļĢāđƒāļ™āļ‚āļ“āļ°āļ—āļĩāđˆāļĒāļąāļ‡āļ„āļ‡āļāļēāļĢāđ€āļĨāļ·āđˆāļ­āļ™āļ—āļĩāđˆāļĨāļ·āđˆāļ™āđ„āļŦāļĨāļ—āļĩāđˆ 60 FPS

āļĢāļēāļĒāļāļēāļĢāļ•āļĢāļ§āļˆāļŠāļ­āļšāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž SwiftUI

  • ✅ āđƒāļŠāđ‰ LazyVStack āļŦāļĢāļ·āļ­ List āđāļ—āļ™ VStack āļŠāļģāļŦāļĢāļąāļšāļ„āļ­āļĨāđ€āļĨāļāļŠāļąāļ™
  • ✅ āđƒāļŠāđ‰ Identifiable āļ”āđ‰āļ§āļĒ ID āļ—āļĩāđˆāđ€āļŠāļ–āļĩāļĒāļĢāđāļĨāļ°āđ„āļĄāđˆāļ‹āđ‰āļģāļāļąāļ™
  • ✅ āļ™āļģ Equatable āļĄāļēāđƒāļŠāđ‰āļŠāļģāļŦāļĢāļąāļšāđ€āļ‹āļĨāļĨāđŒāļ—āļĩāđˆāļ‹āļąāļšāļ‹āđ‰āļ­āļ™
  • ✅ āđāļ„āļŠāđāļĨāļ°āļ›āļĢāļąāļšāļ‚āļ™āļēāļ”āļĢāļđāļ›āļ āļēāļžāļāđˆāļ­āļ™āđāļŠāļ”āļ‡āļœāļĨ
  • ✅ āđ‚āļŦāļĨāļ”āļ‚āđ‰āļ­āļĄāļđāļĨāļĨāđˆāļ§āļ‡āļŦāļ™āđ‰āļēāļ”āđ‰āļ§āļĒ prefetching āļ­āļąāļˆāļ‰āļĢāļīāļĒāļ°
  • ✅ āđ€āļĨāļ·āļ­āļ List āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāđ‚āļ•āđ‰āļ•āļ­āļš (swipe) āļŦāļĢāļ·āļ­ LazyVStack āļŠāļģāļŦāļĢāļąāļšāđ€āļĨāļĒāđŒāđ€āļ­āļēāļ•āđŒāļ—āļĩāđˆāļāļģāļŦāļ™āļ”āđ€āļ­āļ‡
  • ✅ āđƒāļŠāđ‰ pinnedViews āļŠāļģāļŦāļĢāļąāļšāļŠāđˆāļ§āļ™āļŦāļąāļ§āđ€āļ‹āļāļŠāļąāļ™
  • ✅ āđƒāļŠāđ‰āļāļēāļĢāđāļšāđˆāļ‡āļŦāļ™āđ‰āļēāļŠāļģāļŦāļĢāļąāļšāļŠāļļāļ”āļ‚āđ‰āļ­āļĄāļđāļĨāļ‚āļ™āļēāļ”āđƒāļŦāļāđˆ
  • ✅ āļ—āļģ profiling āđ€āļ›āđ‡āļ™āļ›āļĢāļ°āļˆāļģāļ”āđ‰āļ§āļĒ Instruments
  • ✅ āđƒāļŠāđ‰ drawingGroup() āļāļąāļšāļ§āļīāļ§āļ—āļĩāđˆāļĄāļĩāđ€āļ­āļŸāđ€āļŸāļāļ•āđŒāļ āļēāļžāļ—āļĩāđˆāļ‹āļąāļšāļ‹āđ‰āļ­āļ™

āđ€āļĢāļīāđˆāļĄāļāļķāļāļ‹āđ‰āļ­āļĄāđ€āļĨāļĒ!

āļ—āļ”āļŠāļ­āļšāļ„āļ§āļēāļĄāļĢāļđāđ‰āļ‚āļ­āļ‡āļ„āļļāļ“āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

āđāļ—āđ‡āļ

#swiftui
#ios
#performance
#lazyvstack
#swift

āđāļŠāļĢāđŒ

āļšāļ—āļ„āļ§āļēāļĄāļ—āļĩāđˆāđ€āļāļĩāđˆāļĒāļ§āļ‚āđ‰āļ­āļ‡

ViewModifier āļ‚āļ­āļ‡ SwiftUI āļŠāļģāļŦāļĢāļąāļšāļŠāļĢāđ‰āļēāļ‡ design system āļ—āļĩāđˆāļ™āļģāļāļĨāļąāļšāļĄāļēāđƒāļŠāđ‰āđƒāļŦāļĄāđˆāđ„āļ”āđ‰āđƒāļ™ iOS

ViewModifier āđāļšāļšāļāļģāļŦāļ™āļ”āđ€āļ­āļ‡āđƒāļ™ SwiftUI: āļĢāļđāļ›āđāļšāļšāļ—āļĩāđˆāļ™āļģāļāļĨāļąāļšāļĄāļēāđƒāļŠāđ‰āđƒāļŦāļĄāđˆāđ„āļ”āđ‰āļŠāļģāļŦāļĢāļąāļš Design System

āļŠāļĢāđ‰āļēāļ‡ ViewModifier āđāļšāļšāļāļģāļŦāļ™āļ”āđ€āļ­āļ‡āđƒāļ™ SwiftUI āļŠāļģāļŦāļĢāļąāļš design system āļ—āļĩāđˆāļŠāļ­āļ”āļ„āļĨāđ‰āļ­āļ‡āļāļąāļ™ āļĢāļđāļ›āđāļšāļš āđāļ™āļ§āļ—āļēāļ‡āļ›āļāļīāļšāļąāļ•āļīāļ—āļĩāđˆāļ”āļĩāļ—āļĩāđˆāļŠāļļāļ” āđāļĨāļ°āļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āļ—āļĩāđˆāđƒāļŠāđ‰āļ‡āļēāļ™āđ„āļ”āđ‰āļˆāļĢāļīāļ‡āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļˆāļąāļ”āļŠāđ„āļ•āļĨāđŒ view āļ‚āļ­āļ‡ iOS āļ­āļĒāđˆāļēāļ‡āļĄāļĩāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž

āļāļēāļĢāđ€āļ›āļĢāļĩāļĒāļšāđ€āļ—āļĩāļĒāļš @Observable āđāļĨāļ° @State āđƒāļ™ SwiftUI āļŠāļģāļŦāļĢāļąāļšāļ™āļąāļāļžāļąāļ’āļ™āļē iOS

SwiftUI @Observable vs @State: āđƒāļŠāđ‰āļ•āļąāļ§āđ„āļŦāļ™āđ€āļĄāļ·āđˆāļ­āđ„āļŦāļĢāđˆāđƒāļ™āļ›āļĩ 2026

āđ€āļ‚āđ‰āļēāđƒāļˆāļ„āļ§āļēāļĄāđāļ•āļāļ•āđˆāļēāļ‡āļĢāļ°āļŦāļ§āđˆāļēāļ‡ @Observable āđāļĨāļ° @State āđƒāļ™ SwiftUI āđ€āļžāļ·āđˆāļ­āđ€āļĨāļ·āļ­āļāđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­āļˆāļąāļ”āļāļēāļĢ state āļ—āļĩāđˆāđ€āļŦāļĄāļēāļ°āļāļąāļšāđāļ­āļ› iOS

āļ„āļđāđˆāļĄāļ·āļ­ SwiftUI āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļŠāļĢāđ‰āļēāļ‡āļ­āļīāļ™āđ€āļ—āļ­āļĢāđŒāđ€āļŸāļ‹ iOS āļ—āļĩāđˆāļ—āļąāļ™āļŠāļĄāļąāļĒ

SwiftUI: āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡āļ­āļīāļ™āđ€āļ—āļ­āļĢāđŒāđ€āļŸāļ‹āļ—āļĩāđˆāļ—āļąāļ™āļŠāļĄāļąāļĒāļŠāļģāļŦāļĢāļąāļš iOS

āļ„āļđāđˆāļĄāļ·āļ­āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡āļ­āļīāļ™āđ€āļ—āļ­āļĢāđŒāđ€āļŸāļ‹āļ—āļĩāđˆāļ—āļąāļ™āļŠāļĄāļąāļĒāļ”āđ‰āļ§āļĒ SwiftUI: āđ„āļ§āļĒāļēāļāļĢāļ“āđŒāđāļšāļš declarative, āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒ, āđāļ­āļ™āļīāđ€āļĄāļŠāļąāļ™ āđāļĨāļ°āđāļ™āļ§āļ›āļāļīāļšāļąāļ•āļīāļ—āļĩāđˆāļ”āļĩāļ—āļĩāđˆāļŠāļļāļ”āļŠāļģāļŦāļĢāļąāļš iOS 18