简体   繁体   中英

Facing with some strange behaviour of State or Binding in didSet situation in SwiftUI

I am updating my State variable with a Binding from another View, I have some code in didSet of my State, it would fired when I do set value from State, but not from Binding, for this reason I have to give a didSet to Binding of this State, which is not logical for me, Binding should Bind but it makes own version of that value with this advantage of updating State as well, I was wandering if it is a bug or it should be in this way, I mean I am expecting reference type behaviour in term of State-Binding, but with this down code? it shows more like Value type! Why this is happening? I was expecting didSet of State get fired even update coming from Binding!

    import SwiftUI

struct ContentView: View {
    
    @State var someProperty: String = "Empty string!" {
        
        didSet(oldValue) {
            
            print("State didSet → " + someProperty)
            
        }
    }
    
    var body: some View {
        
        Text(someProperty)
            .padding()
        
        ButtonView(someProperty: $someProperty)
        
    }
}


struct ButtonView: View {
    
    @Binding var someProperty: String  {
        
        didSet(oldValue) {
            
            print("Binding didSet → " + someProperty)
            
        }
    }
    
    var body: some View {
        
        Button("update Text") { someProperty = "Hello, world!" }
        
    }
}

update:

    struct ContentView: View {

    @State private var someProperty: String = "Empty string!" {

        didSet(oldValue) {

            print("State didSet → " + someProperty)

        }
    }

    var body: some View {

        Text(someProperty)
            .padding()

        Button("update Text") { someProperty = "Hello, world!" }


    }
}

Use custom binding

var body: some View {
    
    Text(someProperty)
        .padding()
    
    ButtonView(someProperty: Binding(
        get: { self.someProperty },
        set: { self.someProperty = $0 }
    ))
    
}

didSet works with @State only when you modify the @State directly but not when you change its internal value.

Note that the State is a wrapper . If you change its internal value (here _someProperty ) using Binding , then didSet is not called.

You can use onReceive or onChange instead:

import Combine
import SwiftUI

struct ContentView: View {
    @State private var someProperty: String = "Empty string!"

    var body: some View {
        Text(someProperty)
            .padding()
            // updated on changes only
            .onChange(of: someProperty) {
                print("State onChange → " + $0)
            }
            // updated every time
            .onReceive(Just(someProperty)) {
                print("State onReceive → " + $0)
            }

        ButtonView(someProperty: $someProperty)
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM