How to Bind Data Between Parent Model and Child Model Classes in SwiftUI?

I have a Model class containing the main data (@Published var counter: Int), which is automatically updated periodically by a Timer. I am considering displaying the Model.counter value in a SheetView.

I believe a simple case would look like this.

@main
struct BindingSampleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

@MainActor
class ContentModel: ObservableObject {
    
    @Published var counter: Int = 0
    @Published var isShowingSheet = false
    
    init() {
        Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
            Task { @MainActor in
                self.counter += 1
                print("counter: \(self.counter)")
            }
        }
    }
    
    func showSheet() {
        isShowingSheet = true
    }
}

struct ContentView: View {
    
    @StateObject var model = ContentModel()
    
    var body: some View {
        VStack {
            Button() {
                model.showSheet()
            } label: {
                Text("Show. \(model.counter)")
            }
        }
        .sheet(isPresented: $model.isShowingSheet) {
            SheetView(counter: model.counter)
        }
        .padding()
    }
}

struct SheetView: View {
    let counter: Int
    var body: some View {
        VStack {
            Text("\(counter)")
                .font(.largeTitle)
        }
    }
}

Due to the increasing complexity of SheetView's logic, I've created a separate SheetModel. What I want to achieve is to display the value of Model.counter, which is updated by a timer, in SheetView by relaying it through SheetModel.

After some trial and error, I have come up with the following two pieces of code that seem to achieve the desired behavior. However, I am not sure if this is the appropriate way to use SwiftUI.

Specifically, for the first code snippet, self.sheetModel = SheetModel(counter: self._counter), I suspect it may not be ideal because it probably causes both Model and SheetModel to reference the same object.

For the second snippet, SheetModel.init(counter: Published<Int>.Publisher) { counter.assign(to: &self.$counter) }, it feels a bit verbose.

Is there a simpler and better way to bind Model.counter and SheetModel.counter?

(Tested on Xcode Version 14.3.1 (14E300c), iOS simulator 16.4)

First

@main
struct BindingSampleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

@MainActor
class ContentModel: ObservableObject {
    
    @Published var counter: Int = 0
    @Published var sheetModel: SheetModel?
    var isShowingSheet: Bool {
        get {
            sheetModel != nil
        }
        set {
            if !newValue {
                sheetModel = nil
            }
        }
    }
    
    init() {
        Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
            Task { @MainActor in
                self.counter += 1
                print("counter: \(self.counter)")
            }
        }
    }
    
    func showSheet() {
       //  I suspect it may not be ideal because it probably causes both Model and 
       //  SheetModel to reference the same object.
        self.sheetModel = SheetModel(counter: self._counter)  
    }
}

@MainActor
class SheetModel: ObservableObject {
    @Published var counter: Int = 0
    
    init(counter: Published<Int>) {
        print("SheetModel.init")
        self._counter = counter
    }
}

struct ContentView: View {
    
    @StateObject var model = ContentModel()
    
    var body: some View {
        VStack {
            Button() {
                model.showSheet()
            } label: {
                Text("Show. \(model.counter)")
            }
        }
        .sheet(isPresented: $model.isShowingSheet) {
            SheetView(model: model.sheetModel!)
        }
        .padding()
    }
}

struct SheetView: View {
    @ObservedObject var model: SheetModel
    
    var body: some View {
        VStack {
            Text("\(model.counter)")
                .font(.largeTitle)
        }
    }
}

Second


@MainActor
class ContentModel: ObservableObject {
    
    @Published var counter: Int = 0
    @Published var sheetModel: SheetModel?
    var isShowingSheet: Bool {
        get {
            sheetModel != nil
        }
        set {
            if !newValue {
                sheetModel = nil
            }
        }
    }
    
    init() {
        Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
            Task { @MainActor in
                self.counter += 1
                print("counter: \(self.counter)")
            }
        }
    }
    
    func showSheet() {
        self.sheetModel = SheetModel(counter: $counter)
    }
}

@MainActor
class SheetModel: ObservableObject {
    @Published var counter: Int = 0
    
    init(counter: Published<Int>.Publisher) {
        print("SheetModel.init")
       //  it feels a bit verbose.
        counter.assign(to: &self.$counter)
    }
}

// ContentView and SheetView are same as above.
How to Bind Data Between Parent Model and Child Model Classes in SwiftUI?
 
 
Q