返回 Skill 列表
extension
分类: 开发与工程无需 API Key

swift-performance

使用Instruments性能分析、延迟加载、内存管理和视图优化来优化SwiftUI和Swift应用程序的性能。在诊断UI响应慢、修复内存泄漏、优化滚动性能或减少应用程序启动时间时使用。

person作者: jakexiaohubgithub

Swift Performance Optimization

SwiftUI View Optimization

// ❌ BAD - Recreates formatter every render
struct BadView: View {
    var body: some View {
        Text(Date(), formatter: DateFormatter()) // New instance each time!
    }
}

// ✅ GOOD - Cached formatter
struct GoodView: View {
    private static let formatter: DateFormatter = {
        let f = DateFormatter()
        f.dateStyle = .medium
        return f
    }()

    var body: some View {
        Text(Date(), formatter: Self.formatter)
    }
}

// ✅ Use Equatable to prevent unnecessary updates
struct ItemView: View, Equatable {
    let item: Item

    static func == (lhs: Self, rhs: Self) -> Bool {
        lhs.item.id == rhs.item.id
    }

    var body: some View {
        Text(item.name)
    }
}

Lazy Loading

// ✅ LazyVStack for long lists
ScrollView {
    LazyVStack(spacing: 16) {
        ForEach(items) { item in
            ItemRow(item: item)
        }
    }
}

// ✅ LazyView wrapper for heavy views
struct LazyView<Content: View>: View {
    let build: () -> Content

    init(_ build: @autoclosure @escaping () -> Content) {
        self.build = build
    }

    var body: Content {
        build()
    }
}

// Usage - defers initialization
NavigationLink {
    LazyView(HeavyDetailView(item: item))
} label: {
    Text(item.name)
}

Memory Management

// ✅ Avoid retain cycles with weak references
class ViewModel: ObservableObject {
    private var cancellables = Set<AnyCancellable>()

    func observe() {
        NotificationCenter.default
            .publisher(for: .someNotification)
            .sink { [weak self] _ in
                self?.handleNotification()
            }
            .store(in: &cancellables)
    }
}

// ✅ Use value types when possible
struct User: Sendable {  // Struct, not class
    let id: UUID
    let name: String
}

// ✅ Image caching
actor ImageCache {
    private var cache = NSCache<NSString, UIImage>()

    func image(for url: URL) async -> UIImage? {
        let key = url.absoluteString as NSString
        if let cached = cache.object(forKey: key) {
            return cached
        }
        guard let image = await downloadImage(url) else { return nil }
        cache.setObject(image, forKey: key)
        return image
    }
}

Instruments Profiling

| Instrument | Detects | |------------|---------| | Time Profiler | Slow functions, CPU usage | | Allocations | Memory growth, leaks | | Leaks | Retain cycles | | SwiftUI | View body updates, layout | | Core Animation | Offscreen renders, blending |

Common Performance Issues

// ❌ Heavy computation in body
var body: some View {
    let sorted = items.sorted() // Runs every render!
    List(sorted) { ... }
}

// ✅ Move to ViewModel or cache
@Observable class ViewModel {
    var items: [Item] = [] {
        didSet { sortedItems = items.sorted() }
    }
    private(set) var sortedItems: [Item] = []
}

// ❌ Unnecessary state invalidation
@State private var allItems: [Item] = []  // Changes invalidate entire view

// ✅ Use @Observable with granular properties
@Observable class ItemsStore {
    var displayedItems: [Item] = []  // Only this triggers updates
    var metadata: Metadata = .empty   // Independent updates
}

Launch Time Optimization

// ✅ Defer non-essential work
@main
struct MyApp: App {
    init() {
        // Only critical initialization here
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
                .task {
                    // Defer analytics, caching, etc.
                    await DeferredSetup.run()
                }
        }
    }
}

// ✅ Use lazy initialization
class AppServices {
    static let shared = AppServices()
    lazy var analytics = AnalyticsService()  // Created on first use
    lazy var imageCache = ImageCache()
}