gpt4 book ai didi

ios - SwiftUI:如何在后台运行计时器

转载 作者:行者123 更新时间:2023-12-01 19:29:30 25 4
gpt4 key购买 nike

我已经构建了一个基本的计时器应用程序,并且正在尝试弄清楚如何在后台运行计时器。
我试过 后台模式来自 签约和能力 并且似乎不适合我。
我目前正在开发 Xcode 12 beta 6。
代码

struct ContentView: View {
@State var start = false
@State var count = 0

var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

var body: some View {
ZStack {
// App content.
}
.onReceive(timer, perform: { _ in
if start {
if count < 15 {
count += 1
} else {
start.toggle()
}
}
})
}
}
如果你们中的任何人对以更好的方式管理计时器有任何建议,请告诉我。谢谢。

最佳答案

当用户离开应用程序时,它会被暂停。当用户离开应用程序时,通常不会让计时器继续运行。我们不想耗尽用户的电池来更新一个真正不相关的计时器,直到用户返回应用程序。
这显然意味着您不想使用“计数器”模式。相反,捕获 Date当您启动计时器时,并保存它以防用户离开应用程序:

func saveStartTime() {
if let startTime = startTime {
UserDefaults.standard.set(startTime, forKey: "startTime")
} else {
UserDefaults.standard.removeObject(forKey: "startTime")
}
}
并且,当应用程序启动时,检索到保存的 startTime :
func fetchStartTime() -> Date? {
UserDefaults.standard.object(forKey: "startTime") as? Date
}
你的计时器现在不应该使用计数器,而是计算开始时间和现在之间耗时:
let now = Date()
let elapsed = now.timeIntervalSince(startTime)

guard elapsed < 15 else {
self.stop()
return
}

self.message = String(format: "%0.1f", elapsed)

就个人而言,我会从 View 中抽象出这个计时器和持久性的东西。 :
class Stopwatch: ObservableObject {
/// String to show in UI
@Published private(set) var message = "Not running"

/// Is the timer running?
@Published private(set) var isRunning = false

/// Time that we're counting from
private var startTime: Date? { didSet { saveStartTime() } }

/// The timer
private var timer: AnyCancellable?

init() {
startTime = fetchStartTime()

if startTime != nil {
start()
}
}
}

// MARK: - Public Interface

extension Stopwatch {
func start() {
timer?.cancel() // cancel timer if any

if startTime == nil {
startTime = Date()
}

message = ""

timer = Timer
.publish(every: 0.1, on: .main, in: .common)
.autoconnect()
.sink { [weak self] _ in
guard
let self = self,
let startTime = self.startTime
else { return }

let now = Date()
let elapsed = now.timeIntervalSince(startTime)

guard elapsed < 60 else {
self.stop()
return
}

self.message = String(format: "%0.1f", elapsed)
}

isRunning = true
}

func stop() {
timer?.cancel()
timer = nil
startTime = nil
isRunning = false
message = "Not running"
}
}

// MARK: - Private implementation

private extension Stopwatch {
func saveStartTime() {
if let startTime = startTime {
UserDefaults.standard.set(startTime, forKey: "startTime")
} else {
UserDefaults.standard.removeObject(forKey: "startTime")
}
}

func fetchStartTime() -> Date? {
UserDefaults.standard.object(forKey: "startTime") as? Date
}
}
那么 View 就可以使用这个 Stopwatch :
struct ContentView: View {
@ObservedObject var stopwatch = Stopwatch()

var body: some View {
VStack {
Text(stopwatch.message)
Button(stopwatch.isRunning ? "Stop" : "Start") {
if stopwatch.isRunning {
stopwatch.stop()
} else {
stopwatch.start()
}
}
}
}
}

FWIW, UserDefaults可能不是存储此 startTime 的正确位置.我可能会使用 plist 或 CoreData 或其他任何东西。但我想让上面的内容尽可能简单,以说明持久化 startTime 的想法。这样当应用程序再次启动时,您可以让它看起来像计时器在后台运行,即使它不是。

关于ios - SwiftUI:如何在后台运行计时器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63765532/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com