MST

星途 面试题库

面试题:Swift中SwiftUI如何与后台任务配合并更新WidgetKit

假设你正在开发一个iOS应用,使用SwiftUI构建界面,并且需要在后台定期获取数据,然后更新WidgetKit展示的内容。请描述实现这一流程的主要步骤,包括在SwiftUI中如何发起后台任务请求,以及后台任务完成后如何将新数据传递给Widget进行更新。
23.5万 热度难度
编程语言Swift

知识考点

AI 面试

面试题答案

一键面试

1. 在SwiftUI中发起后台任务请求

  1. 配置权限
    • Info.plist文件中添加UIBackgroundModes键,并包含fetch值,以声明应用支持后台获取。
  2. 设置后台任务调度
    • 在AppDelegate中配置后台任务。例如,在SceneDelegate.swiftAppDelegate.swift中:
import UIKit
import UserNotifications

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // 配置后台任务
        let backgroundTaskScheduler = BGTaskScheduler.shared
        backgroundTaskScheduler.register(forTaskWithIdentifier: "com.example.fetchDataTask", using: nil) { task in
            self.handleAppRefresh(task: task as! BGAppRefreshTask)
        }
    }

    func handleAppRefresh(task: BGAppRefreshTask) {
        // 执行数据获取逻辑
        let semaphore = DispatchSemaphore(value: 0)
        let url = URL(string: "https://example.com/api/data")!
        let task = URLSession.shared.dataTask(with: url) { data, response, error in
            // 处理数据
            if let data = data {
                // 保存数据等操作
            }
            semaphore.signal()
        }
        task.resume()
        semaphore.wait()
        task.expirationHandler = {
            task.cancel()
        }
        task.setTaskDescription("Fetching data in background")
        task.earliestBeginDate = Date(timeIntervalSinceNow: 30)
        task.setTaskDescription("Fetching data in background")
        task.earliestBeginDate = Date(timeIntervalSinceNow: 30)
        task.expirationHandler = {
            task.cancel()
        }
        task.resume()
    }
}
  1. 触发后台任务
    • 在合适的时机触发后台任务,例如在应用启动时或根据业务逻辑:
let backgroundTaskScheduler = BGTaskScheduler.shared
let request = BGAppRefreshTaskRequest(identifier: "com.example.fetchDataTask")
request.earliestBeginDate = Date(timeIntervalSinceNow: 0)
do {
    try backgroundTaskScheduler.submit(request)
} catch {
    print("Could not submit background task: \(error)")
}

2. 后台任务完成后将新数据传递给Widget进行更新

  1. 数据存储
    • 后台任务获取到数据后,将数据存储在合适的地方,如UserDefaultsCore Data或文件系统。例如,使用UserDefaults
if let data = data {
    UserDefaults.standard.set(data, forKey: "newData")
}
  1. Widget更新
    • 在Widget的TimelineProvider中监听数据变化并更新Widget内容。例如:
struct Provider: TimelineProvider {
    func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date(), data: nil)
    }

    func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) {
        let entry = SimpleEntry(date: Date(), data: UserDefaults.standard.data(forKey: "newData"))
        completion(entry)
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
        var entries: [SimpleEntry] = []
        let currentDate = Date()
        for _ in 0..<5 {
            let entryDate = Calendar.current.date(byAdding:.minute, value: 1, to: currentDate)!
            let entry = SimpleEntry(date: entryDate, data: UserDefaults.standard.data(forKey: "newData"))
            entries.append(entry)
        }
        let timeline = Timeline(entries: entries, policy:.atEnd)
        completion(timeline)
    }
}
  1. Widget刷新
    • 可以通过WidgetCenter.shared.reloadAllTimelines()方法在数据更新后通知WidgetKit重新加载时间线,以显示新数据。例如,在后台任务完成数据存储后:
import WidgetKit
WidgetCenter.shared.reloadAllTimelines()