Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

Is it reasonable to vend an NSView from a "ViewModel" when using NSViewRepresentable instead of implementing the Coordinator pattern?

I'm currently integrating SwiftUI into an AppKit based application and was curious if the design pattern below was viable or not. In order to "bridge" between AppKit and SwiftUI, most of my SwiftUI "root" views have aViewModel that is accessible to the SwiftUI view via @ObservedObject.

When a SwiftUI views need to use NSViewRepresentable I'm finding the use of a ViewModel and a Coordinator to be an unnecessary layer of indirection. In cases where it makes sense, I've just used the ViewModel as the Coordinator and it all appears to be working ok, but I'm curious if this is reasonable design pattern or if I'm overlooking something.

Consider the following pseudo code:

// 1. A normal @ObservedObject acting as the ViewModel that also owns and manages an NSTableView. 
@MainActor final class ViewModel: ObservedObject, NSTableView... {
  let scrollView: NSScrollView
  let tableView: NSTableView
  @Published var selectedTitle: String
  
  init() {
    // ViewModel manages tableView as its dataSource and delegate.       
    tableView.dataSource = self 
    tableView.delegate = self
  }
  
  func reload() {
    tableView.reloadData()
  }
  
  // Update view model properties. 
  // Simpler than passing back up through a Coordinator.
  func tableViewSelectionDidChange(_ notification: Notification) {
    selectedTitle = tableView.selectedItem.title
  }
}

// 2. A normal SwiftUI view, mostly driven by the ViewModel.
struct ContentView: View {
  
  @ObservedObject model: ViewModel
  
  var body: some View {
    Text(model.selectedTitle)

    // No need to pass anything down other than the view model.
    MyTableView(model: model)
    
    Button("Reload") { model.reload() }
    Button("Delete") { model.deleteRow(...) }
  }
}

// 3. A barebones NSViewRepresentable that just vends the required NSView. No other state is required as the ViewModel handles all interactions with the view.
struct MyTableView: NSViewRepresentable {

  // Can this even be an NSView? 
  let model: ViewModel
    
  func makeNSView(context: Context) -> some NSView {
    return model.scrollView
  }
  
  func updateNSView(_ nsView: NSViewType, context: Context) {
    // Not needed, all updates are driven through the ViewModel.
  }
}

From what I can tell, the above is working as expected, but I'm curious if there are some situations where this could "break", particularly around the lifecycle of NSViewRepresentable

Would love to know if overall pattern is "ok" from a SwiftUI perspective.

Is it reasonable to vend an NSView from a "ViewModel" when using NSViewRepresentable instead of implementing the Coordinator pattern?
 
 
Q