Post

Replies

Boosts

Views

Activity

AsyncPublisher does not buffer values. Is this a bug?
I'm trying out this code in a playground in Xcode 13.2 beta (13C5066c) import _Concurrency import Combine import PlaygroundSupport import Foundation extension Task where Success == Never, Failure == Never {   static func sleep(seconds: Double) async throws {     try await Self.sleep(nanoseconds: UInt64(1e9 * seconds))   } } Task {   let values = PassthroughSubject<Int, Never>()   Task {     var counter = 0     while true {       counter += 1       print("[SEND] \(counter)")       values.send(counter)       try! await Task.sleep(seconds: Double.random(in: 0.1...0.5))     }   }   for await value in values // vvvvvvvvvvvvv         .buffer(size: Int.max, prefetch: .keepFull, whenFull: .dropOldest) // ^^^^^^^^^^^^^         .values {     print("[RECV] \(value)")     try! await Task.sleep(seconds: 1)   } } PlaygroundPage.current.needsIndefiniteExecution = true This is modeled after real application code. For example, values could be a PassthroughSubject<Packet, NWError> (this is, in fact, what my app code looks like) I've noticed that when doing Publisher.values to convert a Publisher into an AsyncPublisher (so we can use for await), the values aren't buffered. In other words, if we are inside of the body of the for await loop and something is sent to the PassthroughSubject, that value is dropped unless we use .buffer beforehand. This is demonstrated in the playground code above. The outer task receives values, but takes 1 second to process them. The inner task sends values at a fast rate (100ms–500ms). This means that values received during that 1 second period are dropped.(without the .buffer call; with that call, the problem goes away) Is this intentional? I believe this should be more prevalent in documentation. The documentation says that AsyncStream has a buffer: An arbitrary source of elements can produce elements faster than they are consumed by a caller iterating over them. Because of this, AsyncStream defines a buffering behavior, allowing the stream to buffer a specific number of oldest or newest elements. By default, the buffer limit is Int.max, which means the value is unbounded. But AsyncPublisher conforms to AsyncSequence, and not AsyncStream. Maybe this is how this can be fixed?
0
0
900
Nov ’21
Performance of selecting table rows
While not a major problem, selecting table rows seems to be noticeably more sluggish compared to other apps that make heavy use of table views (such as Finder). In other words, the time between clicking and the table row visibly highlighting feels longer than in other apps. I assume this is due to some details in SwiftUI that have yet to be sorted out, or is it the fault of the Garden App sample code? Perhaps both?
2
0
958
Jun ’21
Recognize end of two sequenced LongPressGestures
I'm trying to sequence two LongPressGestures, but my onEnded handler isn't being called when the second one finishes. Here is my code:     var timerGesture: some Gesture {         let cautionary = LongPressGesture(minimumDuration: 0.5)             .onEnded { _ in print("cautionary done") }         let lift = LongPressGesture(minimumDuration: .infinity)             .onEnded { _ in print("lift done") }         return cautionary.sequenced(before: lift)     } This gesture manipulates a timer. The point of the gesture is to ensure that the user must long press for at least 0.5 seconds before they may lift their finger in order to start the timer. In other words, there is a 500ms long "confirmation" period where the user must hold down their finger before they can actually complete the gesture. Doing a simple tap will cancel the gesture during cautionary. Here's what I'm trying to accomplish: User long presses for at least 0.5 seconds. After 0.5 seconds, cautionary's onEnded is called. The user releases their finger, and lift's onEnded is called. However, lift's onEnded is never actually called. How can I achieve something like this using SwiftUI's gesture system?
1
0
392
Jun ’20