MST

星途 面试题库

面试题:SwiftUI DatePicker联动与性能优化

假设有两个SwiftUI的DatePicker,一个用于选择日期,另一个用于选择时间(精确到分钟)。要求当日期选择器的日期发生变化时,时间选择器中的时间选项根据该日期的业务规则(例如当天的营业时间为9:00 - 18:00)进行动态更新。并且需要考虑在大量数据更新场景下,如何对这个联动功能进行性能优化,给出详细的设计思路与关键代码实现。
28.6万 热度难度
编程语言Swift

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 日期选择器绑定:使用@State来绑定日期选择器选择的日期。
  2. 时间选择器绑定:同样使用@State来绑定时间选择器选择的时间。
  3. 业务规则函数:创建一个函数,根据传入的日期返回符合业务规则(如9:00 - 18:00)的时间数组。
  4. 动态更新:在日期选择器的onChange闭包中调用业务规则函数,更新时间选择器的可选时间。
  5. 性能优化
    • 缓存机制:对于相同日期多次请求时间数据的情况,使用缓存来避免重复计算。
    • 批量更新:如果有大量数据更新,避免频繁的小更新,而是将更新操作合并,一次性处理。
    • 异步计算:在后台线程计算符合业务规则的时间数据,避免阻塞主线程。

关键代码实现

import SwiftUI

struct ContentView: View {
    @State private var selectedDate = Date()
    @State private var selectedTime: Date?
    private var availableTimes: [Date] = []

    var body: some View {
        VStack {
            DatePicker("选择日期", selection: $selectedDate, displayedComponents:.date)
              .onChange(of: selectedDate) { newDate in
                    availableTimes = getAvailableTimes(for: newDate)
                    if let firstTime = availableTimes.first {
                        selectedTime = firstTime
                    }
                }
            DatePicker("选择时间", selection: $selectedTime, in: availableTimes, displayedComponents:.hourAndMinute)
        }
    }

    private func getAvailableTimes(for date: Date) -> [Date] {
        // 这里简单示例,实际业务可能更复杂
        let calendar = Calendar.current
        let startComponents = DateComponents(calendar: calendar, year: calendar.component(.year, from: date), month: calendar.component(.month, from: date), day: calendar.component(.day, from: date), hour: 9, minute: 0)
        let endComponents = DateComponents(calendar: calendar, year: calendar.component(.year, from: date), month: calendar.component(.month, from: date), day: calendar.component(.day, from: date), hour: 18, minute: 0)
        guard let startTime = calendar.date(from: startComponents), let endTime = calendar.date(from: endComponents) else {
            return []
        }
        var times: [Date] = []
        var currentTime = startTime
        while currentTime <= endTime {
            times.append(currentTime)
            currentTime = calendar.date(byAdding:.minute, value: 1, to: currentTime)!
        }
        return times
    }
}

缓存机制优化

private var timeCache = [Date: [Date]]()
private func getAvailableTimes(for date: Date) -> [Date] {
    if let cachedTimes = timeCache[date] {
        return cachedTimes
    }
    // 这里简单示例,实际业务可能更复杂
    let calendar = Calendar.current
    let startComponents = DateComponents(calendar: calendar, year: calendar.component(.year, from: date), month: calendar.component(.month, from: date), day: calendar.component(.day, from: date), hour: 9, minute: 0)
    let endComponents = DateComponents(calendar: calendar, year: calendar.component(.year, from: date), month: calendar.component(.month, from: date), day: calendar.component(.day, from: date), hour: 18, minute: 0)
    guard let startTime = calendar.date(from: startComponents), let endTime = calendar.date(from: endComponents) else {
        return []
    }
    var times: [Date] = []
    var currentTime = startTime
    while currentTime <= endTime {
        times.append(currentTime)
        currentTime = calendar.date(byAdding:.minute, value: 1, to: currentTime)!
    }
    timeCache[date] = times
    return times
}

异步计算优化

private func getAvailableTimesAsync(for date: Date, completion: @escaping ([Date]) -> Void) {
    if let cachedTimes = timeCache[date] {
        completion(cachedTimes)
        return
    }
    DispatchQueue.global(qos:.userInitiated).async {
        let calendar = Calendar.current
        let startComponents = DateComponents(calendar: calendar, year: calendar.component(.year, from: date), month: calendar.component(.month, from: date), day: calendar.component(.day, from: date), hour: 9, minute: 0)
        let endComponents = DateComponents(calendar: calendar, year: calendar.component(.year, from: date), month: calendar.component(.month, from: date), day: calendar.component(.day, from: date), hour: 18, minute: 0)
        guard let startTime = calendar.date(from: startComponents), let endTime = calendar.date(from: endComponents) else {
            completion([])
            return
        }
        var times: [Date] = []
        var currentTime = startTime
        while currentTime <= endTime {
            times.append(currentTime)
            currentTime = calendar.date(byAdding:.minute, value: 1, to: currentTime)!
        }
        self.timeCache[date] = times
        DispatchQueue.main.async {
            completion(times)
        }
    }
}

onChange中使用异步函数:

.onChange(of: selectedDate) { newDate in
    getAvailableTimesAsync(for: newDate) { times in
        availableTimes = times
        if let firstTime = availableTimes.first {
            selectedTime = firstTime
        }
    }
}