Swift AsyncStream variable, use after finish()

Viewed 347

I'm currently reading about AsyncStreams and as I understand it, they are best for tasks that produce some results over time, but have a lifespan - e.g. start and end. Here's an example I am playing with:

struct AHardWorkingStruct {
    
    lazy var updates = AsyncStream<String> { continuation in
        onProgress = { value in
            continuation.yield(value)
        }
        onFinish = { value in
            continuation.yield(value)
            continuation.finish()
        }
    }
    
    private var onProgress: (String) -> Void = { _ in () }
    private var onFinish: (String) -> Void = { _ in () }
    
    func doSomeWork() async {
        let numbers = (0..<20).map { anInt in
            anInt^2
        }
        
        for number in numbers {
            onProgress("The number is \(number)")
            
            if(number == 20) {
                onFinish("I'm DONE!")
            }
        }
    }
}

I then have AHardWorkingStruct as a property in my view controller and use it like so:

class MyViewController: UIViewController {
    var myHardWorker = AHardWorkingStruct()
    
    @IBAction func tapToRun(_ sender: UIButton) {
        Task {
            await  myHardWorker.doSomeWork()
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        Task {
            for await stream in myHardWorker.updates {
            print(stream)
        }
    }
}

This works perfectly when I tap the button.

However, once I call finish() on the stream, I no longer get the updates from it - which I understand is expected behaviour.

My question is, how can I keep getting updates from a stream that is a variable on a long-lived object? Is there a "reset"? (other than getting rid of the lazy and nilling the variable) I also have a 2nd part to this - what would be the best way to unit test an asyncstream? I've tried using expectations, but not sure if this is right.

0 Answers
Related