Strange crash when using .values from @Published publisher

Given the below code with Swift 6 language mode, Xcode 16.2

  • If running with iOS 18+: the app crashes due to _dispatch_assert_queue_fail

  • If running with iOS 17 and below: there is a warning: warning: data race detected: @MainActor function at Swift6Playground/PublishedValuesView.swift:12 was not called on the main thread

Could anyone please help explain what's wrong here?

import SwiftUI
import Combine

@MainActor
class PublishedValuesViewModel: ObservableObject {
    @Published var count = 0
    @Published var content: String = "NA"
    private var cancellables: Set<AnyCancellable> = []
    
    func start() async {
        let publisher = $count
            .map { String(describing: $0) }
            .removeDuplicates()
        
        for await value in publisher.values {
            content = value
        }
    }
}


struct PublishedValuesView: View {
    @ObservedObject var viewModel: PublishedValuesViewModel
    
    var body: some View {
        Text("Published Values: \(viewModel.content)")
            .task {
                await viewModel.start()
            }
    }
}
let publisher = $count
            .receive(on: DispatchQueue.main)  // receive in the main thread
            .map { String(describing: $0) }
            .removeDuplicates()

I'd like to make my question more clear

I know adding receive(on: DispatchQueue.main) or subscribe(on: DispatchQueue.main would fix this. I know $0 which is the @Published is accessed in background (map function in this case).

What I don't understand are:

  • Why the map run on background, not on main?
  • Why there is discrepancy in iOS 18 and iOS 17 and below.

And interestingly, I observe that the map function run on background only the first time, perhaps the subscription is done in background?

Strange crash when using .values from @Published publisher
 
 
Q