gpt4 book ai didi

Observing @State var changes from UIViewRepresentable in SwiftUI View(观察@State变量在UIView中的变化SwiftUI视图中的可表示)

翻译 作者:bug小助手 更新时间:2023-10-26 21:47:44 28 4
gpt4 key购买 nike



I have the following Swift view:

我有以下几点看法:


struct GameView: View {
@State private var userWon: Bool = false {
didSet {
print("userWon: \(userWon)") // not called
// TODO: Change game state here
}
}

var body: some View {
ZStack {
VStack {
GameViewRepresentable(userWon: $userWon)
.onChange(of: userWon) { newValue in
print("GameViewRepresentable: \(newValue)") // called
// TODO: or change game state here?
}
}
.clipped()
}
}
}

The view representable is like so:

可表示的视图如下所示:


struct GameViewRepresentable: UIViewRepresentable {
typealias UIViewType = GameView
@Binding var userWon: Bool {
willSet { newValue
print("willSet userWon: \(newValue)")
}
didSet {
print("didSet userWon: \(userWon)")
}
}

func makeUIView(context: Context) -> GameView {
let gameView = GameView()
gameView.delegate = context.coordinator
return gameView
}

func updateUIView(_ uiView: GameView, context: Context) {
}

func makeCoordinator() -> GameViewCoordinator {
GameViewCoordinator(self)
}

class GameViewCoordinator: GameViewDelegate {
var parent: GameViewRepresentable

init(_ parent: GameViewRepresentable) {
self.parent = parent
}

func userWon() {
self.parent.userWon = true
}
}
}

I can see that the userWon method is correctly getting called inside the coordinator which correspondingly calls willSet and didSet in GameViewRepresentable, but the didSet in the GameView for the binding userWon property is never called. However the onChange in GameView does get called. So is that the right way to respond to changes to the state property? I was expecting the didSet inside the GameView to get called instead.

我可以看到,在协调器内部正确地调用了userWon方法,该协调器相应地调用了GameView Renatable中的will Set和didSet,但绑定的userWon属性的Gameview中的didSet从未被调用。然而,Gameview中的onChange确实会被调用。那么,这是应对国有资产变化的正确方式吗?我原以为会调用Gameview中的didSet。


更多回答
优秀答案推荐

Yes, onChange is how you detect @State changes.

是的,onChange是您检测@State更改的方式。


It is perfectly normal for willSet and didSet to not be triggered on a @State or @Binding. Swift inserts calls to willSet and didSet in the setter of the userWon property, so if userWon changes not by calling userWon's setter, then willSet and didSet will not be called.

在@State或@绑定上不触发will Set和didSet是非常正常的。SWIFT在userWon属性的setter中插入对will Set和didSet的调用,因此如果没有通过调用userWon的setter来更改userWon,则不会调用will Set和didSet。


Your userWon property lowers to something like this:

您的userWon属性的值如下所示:


private var _userWon = State(initialValue: false)
private var userWon: Bool {
get { _userWon.wrappedValue }
set {
// <willSet is called here>
_userWon.wrappedValue = newValue
// <didSet is called here>
}
}
private var $userWon: Binding<Bool> {
_userWon.projectedValue
}

Consider this really simple example:

考虑一下这个非常简单的例子:


@State private var userWon: Bool = false {
willSet {
print("willSet")
}
didSet {
print("didSet")
}
}

var body: some View {
Toggle(isOn: $userWon) {
Text("Foo")
}
}

No matter how many times I toggle the toggle, willSet and didSet are not called. This is because the Toggle doesn't actually change the value of userWon by literally saying e.g. userWon = true (which would have called its setter). Toggle doesn't know that userWon exists at all.

无论我切换开关多少次,都不会调用will Set和didSet。这是因为Togger实际上并没有通过字面意思改变userWon的值,例如,userWon=True(这将调用它的setter)。Togger根本不知道userWon的存在。


What actually happens is you passed a Binding<Bool> to the Toggle, which was the projectedValue of the State. $userWon is just a short way of saying _userWon.projectedValue. The Toggle will at some point set the wrappedValue property of the Binding<Bool>. This will then cause the wrappedValue of the State to be set, and the view gets updated.

实际发生的情况是,您将一个绑定 传递给了Togger,这是State的ProjectedValue。$userWon只是_userWon.project tedValue的缩写。Togger将在某个时刻设置绑定 的wrapedValue属性。然后,这将导致设置State的wrappeValue,并更新视图。


Notice that everything is done through the wrappedValue properties of State and Binding, not your userWon property.

请注意,所有操作都是通过State和Binding的wrapedValue属性完成的,而不是通过您的userWon属性。



You need to implement updateUIView, e.g.

您需要实现更新UIView,例如


   func updateUIView(_ uiView: GameView, context: Context) {
context.coordinator.parent = self
}

Note, it would be better practice to set new closures on the coordinator instead.

注意,更好的做法是在协调器上设置新的闭包。


更多回答

Unless Apple has it wrong I don’t think it is a mistake developer.apple.com/tutorials/swiftui/interfacing-with-uikit

除非苹果错了,否则我不认为这是错的,developer.apple.com/tutorials/swiftui/interfacing-with-uikit

it's a mistake, sometimes those tutorials are written by interns

这是个错误,有时这些教程是实习生写的

Fruta PaymentButton has done in a different way that also works

Fruta PaymentButton以一种不同的方式做到了这一点

It is just a style choice like many other things, I’ve said it before my only issue with some of your posts is the absoluteness of your choice of words.

这只是一种风格选择,就像许多其他事情一样,我在我对你的一些帖子唯一的问题是你的措辞的绝对性之前已经说过了。

developer.apple.com/wwdc22/10075

developer.apple.com/wwdc22/10075

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com