Swift async func to run sequentially

Overview

  • I have an async function (swift concurrent function) that I would like to execute every time a notification is fired.
  • I would like the async function to run sequentially (the function should complete before next one begins)

My attempt:

  • This is not the actual project, I have tried to simulate a simplified example posted below
  • It could be possible that in trying to simulate the problem I have created an incorrect code to simulate the problem.

Questions:

  • Does this guarantee sequential execution?
  • Or is there a better approach? (using combine or DispatchQueue or some other way?)

Code

extension Notification.Name {
    static let dummy = Notification.Name(rawValue: "dummy")
}

let notifications = NotificationCenter.default.notifications(named: .dummy)
let merger = Merger()
var counter = 0

class Merger {
    func processChanges(forCounter counter: Int) async throws {
        print("process \(counter) started")
        try await Task.sleep(nanoseconds: 6_000_000_000)
        print("process \(counter) ended")
    }
}

let anyCancellable = Timer.TimerPublisher(interval: 1, runLoop: .main, mode: .default)
    .autoconnect()
    .sink { _ in
//        print("timer fired")
        NotificationCenter.default.post(name: .dummy, object: nil)
    }
try? await merger.processChanges(forCounter: counter + 100)

for await notification in notifications {
    counter += 1
    try await merger.processChanges(forCounter: counter)
}

As written, yes. The call to try await merger.processChanges(forCounter: counter) will suspend that loop for as long as it takes processChanges to return. Until processChanges has run to completion (including anything that it itself awaits on, such as Task.sleep), the next iteration will not happen.

1 Like

@lukasa Thanks a lot for clear explanation as to why it works.

In the real world, the next challenge for me is to ensure everything passed to processChanges is sendable and there is that clear separation and nothing crosses concurrency boundaries (which I often encounter)