Является ли didSet специфичным для файла @Binding?

0

Вопрос

По сути, я гнездюсь @Binding 3 слоя в глубину.

struct LayerOne: View {
    @State private var doubleValue = 0.0
    
    var body: some View {
        LayerTwo(doubleValue: $doubleValue)
    }
}

struct LayerTwo: View {
    @Binding var doubleValue: Double {
        didSet {
            print(doubleValue)
        }
    }
    
    var body: some View {
        LayerThree(doubleValue: $doubleValue)
    }
}

struct LayerThree: View {
    @Binding var doubleValue: Double {
        didSet {
            print(doubleValue) // Only this print gets run when doubleValue is updated from this struct
        }
    }

    var body: Some view {
        // Button here changes doubleValue
    }
}

Какую бы структуру я ни изменил doubleValue в том, где находится didSet будет запущен, так что, например, если я изменю его в LayerThree только этот будет напечатан, ни один из остальных не будет.

Я могу следить за изменениями с помощью .onChange(of: doubleValue) который затем будет запущен, когда он изменится, но для меня это не имеет смысла, почему didSet не будет выполняться, кроме как в структуре, в которой она была изменена.

Является @Binding конкретная структура?

swift swiftui
2021-11-22 18:09:26
3

Лучший ответ

1

Использование наблюдателей свойств, таких как didSet о значениях, завернутых в PropertyWrappers не будет иметь "нормального" эффекта, потому что значение устанавливается внутри оболочки.

В SwiftUI, если вы хотите инициировать действие при изменении значения, вам следует использовать onChange(of:perform:) модификатор.

struct LayerTwo: View {
    @Binding var doubleValue: Double
    
    var body: some View {
        LayerThree(doubleValue: $doubleValue)
          .onChange(of: doubleValue) { newValue 
            print(newValue)
          }
    }
}
2021-11-22 18:26:49

Попался, так что, как я и думал... он устанавливается изнутри структуры, в которой он установлен, а не по цепочке.
Joe Scotto
0

Теперь все работает:

struct ContentView: View {
    
    var body: some View {
        
        LayerOne()
        
    }
    
}


struct LayerOne: View {
    
    @State private var doubleValue:Double = 0.0 {
        didSet {
            print("LayerOne:", doubleValue)
        }
    }
    
    var body: some View {
        LayerTwo(doubleValue: Binding(get: { return doubleValue }, set: { newValue in doubleValue = newValue } ))
    }
    
}

struct LayerTwo: View  {
    
    @Binding var doubleValue: Double {
        didSet {
            print("LayerTwo:", doubleValue)
        }
    }
    
    var body: some View {
        
        LayerThree(doubleValue: Binding(get: { return doubleValue }, set: { newValue in doubleValue = newValue } ))
    }
}




struct LayerThree: View  {
    
    @Binding var doubleValue: Double {
        didSet {
            print("LayerThree:", doubleValue) 
        }
    }
    
    var body: some View {
        
        Text(String(describing: doubleValue))
            
        Button("update value") {
            doubleValue = Double.random(in: 0.0...100.0)
        }
        .padding()
    }
    
}

результаты печати:

LayerOne: 64,58963263686678

Два слоя: 64.58963263686678

Три слоя: 64,58963263686678

2021-11-22 18:20:58

Но зачем вам нужно передавать привязку таким образом? Не должен didSet срабатывает независимо от того, где изменена привязка?
Joe Scotto

Я думаю, мы не можем спрашивать, почему или как, потому что это Apple и закрытый исходный код. Для того, чтобы didSet начал работать, вам нужна инициализация для привязки.
swiftPunk
0

Чтобы понять, почему это происходит, мы можем раскрыть синтаксический сахар оболочек свойств. @Binding var doubleValue: Double переводится как:

private var _doubleValue: Binding<Double>
var doubleValue: Double {
    get { _doubleValue.wrappedValue }
    set { _doubleValue.wrappedValue = newValue }
}

init(doubleValue: Binding<Double>) {
    _doubleValue = doubleValue
}

Что бы вы ни делали в didSet будет поставлен после строки _doubleValue.wrappedValue = newValue. Должно быть совершенно очевидно, почему при обновлении doubleValue в слое 3, didSet от doubleValue в слое 2 или 1 не вызывается. Это просто разные вычисляемые свойства!

Решение swiftPunk работает путем создания новой привязки, установщик которой задает структуру doubleValue, следовательно, вызывая didSet:

Binding(get: { return doubleValue }, 
        set: { newValue in doubleValue = newValue }
//                         ^^^^^^^^^^^^^^^^^^^^^^
//                         this will call didSet in the current layer
2021-11-22 18:37:59

На других языках

Эта страница на других языках

Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................