Does @Binding work in Command Line App?

Hello. I need a direction how SwiftUI work. And I assembled simple command line app:

import SwiftUI


struct Button {
    @Binding var target: Int
    func tap() {
        target += 1
    }
}

struct BindingApp {
    
    func run() {
        @State var target = 0
        let button = Button(target: $target)
        while true {
            guard let _ = readLine() else { continue }
            button.tap()
            print("target: \(target)")
        }
    }
    
}

After run in terminal it prints:

d

target: 0

d

target: 0

It means that the variable @State var target = 0 in function run() of struct BindingApp does not receive any effect from instance of button where it was passed. Why? Also I have another question. Why the method tap() of Button structure does not require to be mutating despite the fact that it mutates its value property, as Binding is a structure. I would be grateful if you would drop me a lecture that explains what Binding is (a class or not:).

1 Like

@State and other SwiftUI magic needs to be inflated to really work. It needs to be part of SwiftUI.View or SwiftUI.Scene, which in turn needs to be part of the hierarchy owned by HostingController or @main.

Under the hood, @State has a two stored properties: one contains an initial value and never changes, and a second one contains a reference to Location object which is initially nil. When View or Scene is mounted, SwiftUI uses runtime metadata to find all the magical properties like @State and initialize Location. Setting value to @State, changes it inside the Location. But if location was never initialized, you will have only the initial value. I’m surprised SwiftUI does assert in this case.

I’m not 100% sure what you want to achieve, but I have a gut feeling that ObservableObject will help you. It is part of Combine, and will work fine in command line app or in unit tests. And when you have UI, it will integrate with SwiftUI nicely.

Note that creating a Binding to a property of the ObservableObject from a reference stored in @ObservedObject, @StateObject or @EnvironmentObject is still part of SwiftUI machinery and may not work outside hosted SwiftUI hierarchy.

3 Likes