This is a companion discussion topic for the original entry at https://www.raywenderlich.com/18176818-your-first-ios-and-swiftui-app-polishing-the-app/lessons/27
This is a companion discussion topic for the original entry at https://www.raywenderlich.com/18176818-your-first-ios-and-swiftui-app-polishing-the-app/lessons/27
In ContentView.swift we check to see if alertIsVisible == true before we call PointsView(). So if I understand correctly, there is no need to pass-in $alertIsVisible to the method because that particular value that is being passed-in is not used by the method. It only sets alertIsVisible back to false.
However, as Iâm typing this I think that I have answered my own question⊠the passing-in of the alertIsVisible var is necessary so that the new false value that PointsView() sets is also set to the binding within the view and thus, that new false value is applied to the state variable of the same name in ContentView.swift
@webdevbyalex Youâve got it right. Hereâs another way to think of it:
- In SwiftUI, every piece of state data should have a âsource of truth / ownerâ. For the
alertIsVisible
state, the âsource of truth / ownerâ isContentView
. We can clearly see this because itâs marked as@State
in ContentView.swift. - In SwiftUI, whenever you want another view to access a piece of state data owned elsewhere, you make a binding to that state data (which I sometimes like to think of as a âreferenceâ). In this case, we want
PointsView
to access thealertIsVisible
, which is owned byContentView
. So, we make a@Binding
in ContentView.swift to store a reference toalertIsVisible
(which happens to have the exact same name, but we could have given it a different name). Then inContentView
, we use$
to convert the state variable to a binding, and pass that to our newPointsView
. - At this point, the
alertIsVisible
inContentView
andPointsView
are the pointing to the same piece of data, so if we set it to false in one place, itâs false in the other place, etc.
I hope this makes sense!
Thanx for that thorough explanation Ray!
Iâm seing a strange behaviour with the ternary conditional operator.
Iâm using it exactly the way Ray is doing that.
InstructionsView(game: $game)
.padding(.bottom, alertIsVisible ? 0 : 100)
If I resume the preview it gives me the following error:
"Compiling failed: result values in â? :â expression have mismatching types âIntâ and âCGFloatâ
If I build and run the project in the simulator everything is fine.
I changed the code to:
InstructionsView(game: $game)
.padding(.bottom, alertIsVisible ? CGFLoat(0) : 100)
Then the preview is working correctly.
Iâm using Xcode 12.5 (12E262)
I got the same issue in the next lesson with shapes.swift
Yep I see the same behavior. As of Xcode 12.5, you now need to manually cast Int
s to CGFloat
s / etc. as youâve done here.
For more information, see this thread (@zhongdongy has a nice explanation): SwiftUI Views | raywenderlich.com - #6 by zhongdongy
You give me the answer! Thanks!
Then sliderValue in PointsView.swift can detach @Binding ?
just let sliderValue: Double
I am getting an error that I canât seem to find the solution for. In this part of the code, I get the error âCannot convert value of type âBindingâ to expected argument type âBindingââ.
static var previews: some View {
PointsView(alertIsVisible: alertIsVisible, sliderValue: sliderValue, game: game)
PointsView(alertIsVisible: alertIsVisible, sliderValue: sliderValue, game: game)
.previewLayout(.fixed(width: 568, height: 320))
PointsView(alertIsVisible: alertIsVisible, sliderValue: sliderValue, game: game)
.preferredColorScheme(.dark)
PointsView(alertIsVisible: alertIsVisible, sliderValue: sliderValue, game: game)
.preferredColorScheme(.dark)
.previewLayout(.fixed(width: 568, height: 320))
}