使用Swift Combine创建计时器发布器

时间:2019-07-25 10:33:46

标签: swift swiftui publisher combine

我一直在看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
    }
  }
}

5 个答案:

答案 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
        }
    }
}