Xcode 14: Publishing changes from within view updates

After updating to Xcode 14.0 beta 5 (14A5294e) I'm seeing runtime warnings on iOS when simply changing a published variable from within a button's action.

I'm wondering if this is a false positive on the warning or if there is a new pattern we're supposed to be following here.

This appears to only happen on iOS. The same reproducing code does not output that warning while running on macOS.

Here's a contrived yet complete example that reproduces it on an iPhone 13 Pro simulator while running Xcode 14 beta 5. Does not reproduce the warning when running on Ventura.



class ViewModel: ObservableObject {
    @Published var sheetVM: SheetVM?

    func showSheet() {
        sheetVM = SheetVM(delegate: self)
    }

}

extension ViewModel: SheetDelegate {
    func close() {
        sheetVM = nil
    }

}

class SheetVM: ObservableObject, Identifiable {

    weak var delegate: SheetDelegate?

    init(delegate: SheetDelegate) {
        self.delegate = delegate
    }

    func close() {
        delegate?.close()
    }
}

protocol SheetDelegate: AnyObject {
    func close()
}

struct ContentView: View {

    @ObservedObject
    var viewModel: ViewModel

    var body: some View {
        VStack {
            Button {
                viewModel.showSheet()
            } label: {
                Text("Show Sheet")
            }
        }
        .padding()
        .sheet(item: $viewModel.sheetVM) { sheetVM in
            SheetView(sheetVM: sheetVM)
        }
    }
}

struct SheetView: View {

    let sheetVM: SheetVM

    var body: some View {
        NavigationView {
            Text("Sheet View")
                .toolbar {
                    ToolbarItem(placement: .automatic) {
                        Button {
                            sheetVM.close()
                        } label: {
                            Text("Done")
                                .fontWeight(.semibold)

                        }

                    }

                }
        }

    }

}

Here's the warning and trace while tapping done on the sheet:

warning run: Publishing changes from within view updates is not allowed, this will cause undefined behavior.

Thread 1
#0	0x0000000000000000 in ___lldb_unnamed_symbol155969 ()
#1	0x0000000000000000 in ___lldb_unnamed_symbol155968 ()
#2	0x0000000000000000 in ___lldb_unnamed_symbol155988 ()
#3	0x0000000000000000 in ___lldb_unnamed_symbol180158 ()
#4	0x0000000000000000 in ObservableObjectPublisher.Inner.send() ()
#5	0x0000000000000000 in ObservableObjectPublisher.send() ()
#6	0x0000000000000000 in PublishedSubject.send(_:) ()
#7	0x0000000000000000 in specialized static Published.subscript.setter ()
#8	0x0000000000000000 in static Published.subscript.setter ()
#9	0x0000000000000000 in ViewModel.sheetVM.setter ()
#10	0x0000000000000000 in key path setter for ViewModel.sheetVM : ViewModel ()
#11	0x0000000000000000 in NonmutatingWritebackBuffer.__deallocating_deinit ()
#12	0x0000000000000000 in _swift_release_dealloc ()

I face the same problem. Chaning even a simple @Published property like Int from 1 to 2 in button action triggers the purple warning: "Publishing changes from within view updates is not allowed, this will cause undefined behavior." I believe it's an Xcode bug.

This code was producing the same warning:

struct AreaMap: View {

  @Binding var region: MKCoordinateRegion

  var body: some View {
    Map(coordinateRegion: $region)
  }
}

Where region was passed in the initializer of AreaMap from its parent view.

This resolved the issue:

struct AreaMap: View {

  @Binding var region: MKCoordinateRegion

  var body: some View {
    let binding = Binding(
      get: { self.region },
      set: { newValue in
        DispatchQueue.main.async {
          self.region = newValue
        }
      }
    )
    return Map(coordinateRegion: binding)
  }
}

For what it's worth, I'm no longer seeing the error when running on a 16.1 simulator.

I send feedback to Apple and received answer to retest this with iOS 16.2. After retesting this is not longer shown as a warning so it looks like Apple has fixed it behind the scenes.

Xcode 14: Publishing changes from within view updates
 
 
Q