Skip to content

Instantly share code, notes, and snippets.

@atierian
Created August 12, 2022 18:00
Show Gist options
  • Save atierian/c7c78e7c37c79dab98e68c6b35865b41 to your computer and use it in GitHub Desktop.
Save atierian/c7c78e7c37c79dab98e68c6b35865b41 to your computer and use it in GitHub Desktop.
Subscribing to AsyncSequence vs Combine Publisher
actor Counter: AsyncSequence {
typealias Element = Int
let limit: Int
var current = 1
init(limit: Int, current: Int = 1) {
self.limit = limit
self.current = current
}
func increment() {
current += 1
}
nonisolated func makeAsyncIterator() -> Iterator {
Iterator(counter: self)
}
}
extension Counter {
struct Iterator: AsyncIteratorProtocol, Sendable {
let counter: Counter
mutating func next() async -> Int? {
guard !Task.isCancelled else {
return nil
}
guard await counter.current < counter.limit else {
return nil
}
try! await Task.sleep(nanoseconds: 1 * NSEC_PER_SEC)
let result = await counter.current
await counter.increment()
return result
}
typealias Element = Int
}
}
struct AsyncSequenceCounterView: View {
let counter: Counter
init() {
counter = .init(limit: 10)
}
var body: some View {
Text("Hello, world!")
.padding()
.task {
async let sub1: () = sub1()
async let sub2: () = sub2()
await [sub1, sub2]
}
}
func sub1() async {
print(#function, "called")
for try await count in counter {
print("sub1", count)
}
}
func sub2() async {
print(#function, "called")
for try await count in counter {
print("sub2", count)
}
}
}
sub1() called
sub2() called
sub2 1
sub1 2
sub2 3
sub1 4
sub1 5
sub2 6
sub1 7
sub2 8
sub1 9
sub2 10
import Combine
class PublisherCounterViewModel: ObservableObject {
@Published var current = 1
let limit: Int
var cancellables = Set<AnyCancellable>()
var timer: Timer?
init(limit: Int) {
self.limit = limit
timer = Timer.scheduledTimer(
withTimeInterval: 1,
repeats: true
) { _ in
if self.current < limit {
DispatchQueue.main.async {
self.current += 1
}
} else {
self.timer = nil
}
}
}
}
struct PublisherCounterView: View {
let viewModel = PublisherCounterViewModel(limit: 10)
var body: some View {
Text("Hello, world!")
.padding()
.task {
sub1()
sub2()
}
}
func sub1() {
print(#function, "called")
viewModel.$current.sink { count in
print("sub1", count)
}
.store(in: &viewModel.cancellables)
}
func sub2() {
print(#function, "called")
viewModel.$current.sink { count in
print("sub2", count)
}
.store(in: &viewModel.cancellables)
}
}
sub1() called
sub1 1
sub2() called
sub2 1
sub1 2
sub2 2
sub1 3
sub2 3
sub1 4
sub2 4
sub1 5
sub2 5
sub1 6
sub2 6
sub1 7
sub2 7
sub1 8
sub2 8
sub1 9
sub2 9
sub1 10
sub2 10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment