gpt4 book ai didi

SwiftUI ObjectBinding 不会使用 combine 从可绑定(bind)对象接收 didchange 更新

转载 作者:搜寻专家 更新时间:2023-11-01 06:51:00 25 4
gpt4 key购买 nike

我正在测试 Combine 框架并使用 BindableObject 作为通知中心,以便在 SwiftUI ContentView 的多个 View 之间传递数据。

其中一个 View 是一个表。我单击一行,在打印检查点中检测到该值,因此可绑定(bind)对象收到更新。

问题是,新字符串没有广播到 ContentView 的接收端。

我是新手。

带有 TableView 的 View Controller .swift(广播器):

import SwiftUI
import Combine

final public class NewestString: BindableObject {

public var didChange = PassthroughSubject<NewestString, Never>()

var newstring: String {
didSet {
didChange.send(self)
print("Newstring: \(newstring)") //<-- Change detected
}
}

init(newstring: String) {
self.newstring = newstring
}

public func update() {
didChange.send(self)
print("--Newstring: \(newstring)")

}

}



final class AViewController: UIViewController {

@IBOutlet weak var someTableView: UITableView!
var returnData = NewestString(newstring:"--")

override func viewDidLoad() {
super.viewDidLoad()

}

}

/// [.....] More extensions here

extension AViewController: UITableViewDelegate {

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let completion = someResults[indexPath.row]

//// [......] More code here

self.returnData.newstring = "Test string" //<--- change caused
}
}
}

主要内容 View (广播目的地):

import SwiftUI
import Combine

struct PrimaryButton: View {
var title: String = "DefaultTitle"
var body: some View {
Button(action: { print("tapped") }) {
Text(title)
}
}

}


struct MyMiniView: View {
@State var aTitle: String = "InitialView"
var body: some View {
VStack{
PrimaryButton(title: aTitle)
}
}
}


struct ContentView: View {

@State private var selection = 0
@ObjectBinding var desiredString: NewestString = NewestString(newstring: "Elegir destino") // <-- Expected receiver

var body: some View {

TabbedView(selection: $selection){

ZStack() {

MyMiniView(aTitle: self.desiredString.newstring ?? "--")
// expected end use of the change, that never happens
[...]
}

struct AView: UIViewControllerRepresentable {

typealias UIViewControllerType = AViewController


func makeUIViewController(context: UIViewControllerRepresentableContext<AView>) -> AViewController {


return UIStoryboard(name: "MyStoryboard", bundle: nil).instantiateViewController(identifier: String(describing: AViewController.self)) as! AViewController

}

func updateUIViewController(_ uiViewController: AViewController, context: UIViewControllerRepresentableContext<AView>) {
//
}


它编译、运行并打印更改,但 MyMiniView 的 PrimaryButton 没有更新。

最佳答案

我找不到您在哪里使用 AViewController 的实例,但问题是您正在使用可绑定(bind)对象 NewestString 的多个实例。

ContentView 作为NewestString 的实例,每次更新都会触发 View 重新加载。

struct ContentView: View {

@State private var selection = 0

// First instance is here
@ObjectBinding var desiredString: NewestString = NewestString(newstring: "Elegir destino") // <-- Expected receiver
}

NewestString 的第二个实例在您实际修改的 AViewController 中。但是,由于它不是 NewestString 的同一个实例(实际在内容 View 中声明的实例),修改它不会触发 View 重新加载。

final class AViewController: UIViewController {

@IBOutlet weak var someTableView: UITableView!
// The second instance is here
var returnData = NewestString(newstring:"--")
}

要解决这个问题,您需要找到一种方法将在您的 ContentView 中创建的 NewestString 实例“转发”到 View Controller 。

编辑:找到了一种将 ObjectBinding 的实例传递给 View Controller 的方法:

当您使用 SwiftUI 将 View 添加到层​​次结构中时,您需要传递一个 Binding 值,您希望从 View Controller 访问该值:

struct ContentView: View {
@ObjectBinding var desiredString = NewestString(newstring: "Hello")

var body: some View {
VStack {
AView(binding: desiredString[\.newstring])
Text(desiredString.newstring)
}
}
}

The subscript with a key path will produce a Binding of the given property:

protocol BindableObject {
subscript<T>(keyPath: ReferenceWritableKeyPath<Self, T>) -> > Binding<T> { get }
}

在 View Controller 包装器 (UIViewControllerRepresentable) 中,您需要将给定的 Binding 转发给实际的 View Controller 实例。

struct AView: UIViewControllerRepresentable {
typealias UIViewControllerType = AViewController

var binding: Binding<String>

func makeUIViewController(context: UIViewControllerRepresentableContext<AView>) -> AViewController {
let controller = AViewController()
controller.stringBinding = binding // forward the binding object
return controller
}

func updateUIViewController(_ uiViewController: AViewController, context: UIViewControllerRepresentableContext<AView>) {

}
}

然后,在您的 View Controller 中,您可以使用绑定(bind)来更新您的值(使用 .value 属性):

final class AViewController: UIViewController {
var stringBinding: Binding<String>!

override func viewDidLoad() {
super.viewDidLoad()
stringBinding.value = "Hello world !!"
}
}

当调用 View Controller 的viewDidLoad时,desiredString(在ContentView中)将被更新为“Hello world!!”,只是就像显示的文本 (Text(desiredString.newstring))。

关于SwiftUI ObjectBinding 不会使用 combine 从可绑定(bind)对象接收 didchange 更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57054916/

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