我一直在看Data Flow Through SwiftUI WWDC talk。他们有一张带有示例代码的幻灯片,其中他们使用一个Timer发布者连接到SwiftUI视图,并随时间更新UI。
我正在编写一些代码,希望做完全相同的事情,但是无法弄清楚如何实现此PodcastPlayer.currentTimePublisher
,然后将其连接到UI结构。我还看了所有关于Combine的视频。
我该如何实现?
示例代码:
struct PlayerView : View {
let episode: Episode
@State private var isPlaying: Bool = true
@State private var currentTime: TimeInterval = 0.0
var body: some View {
VStack { // ...
Text("\(playhead, formatter: currentTimeFormatter)")
}
.onReceive(PodcastPlayer.currentTimePublisher) { newCurrentTime in
self.currentTime = newCurrentTime
}
}
}
答案 0 :(得分:3)
我实现了具有新功能的合并计时器,使您可以在不同的时间间隔之间进行切换。
getdate
要启动计时器,只需订阅class CombineTimer {
private let intervalSubject: CurrentValueSubject<TimeInterval, Never>
var interval: TimeInterval {
get {
intervalSubject.value
}
set {
intervalSubject.send(newValue)
}
}
var publisher: AnyPublisher<Date, Never> {
intervalSubject
.map {
Timer.TimerPublisher(interval: $0, runLoop: .main, mode: .default).autoconnect()
}
.switchToLatest()
.eraseToAnyPublisher()
}
init(interval: TimeInterval = 1.0) {
intervalSubject = CurrentValueSubject<TimeInterval, Never>(interval)
}
}
属性。
publisher
您可以通过更改SomeView()
.onReceive(combineTimer.publisher) { date in
// ...
}
属性来切换具有不同间隔的新计时器。
interval
答案 1 :(得分:3)
ObservableObject
要使用Swift Combine创建一个计时器发布器
class TimeCounter: ObservableObject {
@Published var time = 0
lazy var timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in self.time += 1 }
init() { timer.fire() }
}
就是这样!现在您只需要观察变化:
struct ContentView: View {
@ObservedObject var timeCounter = TimeCounter()
var body: some View {
Text("\(timeCounter.time)")
}
}
答案 2 :(得分:0)
我相信那是留给读者的练习。
请注意,它本身不是计时器发布者,而是播客中当前时间的发布者,也就是说,只有当currentTime更改时,它才不会定期发布。
有一个名为@Published的属性包装器,应该可以处理此问题,但我还没有尝试过: https://developer.apple.com/documentation/combine/published
答案 3 :(得分:0)
这里有一个合并计时器的示例。我使用的是全局变量,但是您当然应该使用适用于您的方案的任何变量(environmentObject,State等)。
import SwiftUI
import Combine
class MyTimer {
let currentTimePublisher = Timer.TimerPublisher(interval: 1.0, runLoop: .main, mode: .default)
let cancellable: AnyCancellable?
init() {
self.cancellable = currentTimePublisher.connect() as? AnyCancellable
}
deinit {
self.cancellable?.cancel()
}
}
let timer = MyTimer()
struct Clock : View {
@State private var currentTime: Date = Date()
var body: some View {
VStack {
Text("\(currentTime)")
}
.onReceive(timer.currentTimePublisher) { newCurrentTime in
self.currentTime = newCurrentTime
}
}
}
答案 4 :(得分:0)
从0到9运行的计时器。
struct PlayerView : View {
@State private var currentTime: TimeInterval = 0.0
@ObservedObject var player = PodcastPlayer()
var body: some View {
Text("\(Int(currentTime))")
.font(.largeTitle)
.onReceive(player.$currentTimePublisher.filter { $0 < 10.0 }) { newCurrentTime in
self.currentTime = newCurrentTime
}
}
}
class PodcastPlayer: ObservableObject {
@Published var currentTimePublisher: TimeInterval = 0.0
init() {
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
self.currentTimePublisher += 1
}
}
}