对 SwiftUI 相当陌生,所以提前谢谢您。在 Coordinator 的 init 内部,我们传递 WebView 让 Coordinator 知道父级是谁,但是 WebView 是一个结构体,Coordinator 不会拥有 WebView 的新副本而不是原始 WebView 吗?
如果是这样,为什么这种方法经常被提及?是不是创建一个新的类(ObservableObject)并让WebView创建该类的对象并将该类传递给Coordinator是不是更好?
struct WebView: UIViewRepresentable {
var url: URL
func makeCoordinator() -> WebView.Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> WKWebView {
let view = WKWebView()
view.navigationDelegate = context.coordinator
view.load(URLRequest(url: url))
return view
}
func updateUIView(_ uiView: WKWebView, context: Context) {}
class Coordinator: NSObject, WKNavigationDelegate {
var parent: WebView
init(_ parent: WebView) {
self.parent = parent
}
}
}
是的,
Coordinator
持有原版WebView
的副本,你理解得没错。但它的目的并不是你想象的那样。
首先,您需要了解
WebView
并不包含 WKWebView
,其目的是提供如何更新 WKWebView
以满足您的意图的信息,而 Coordinator
则通过保留 WebView
的副本来帮助它
有什么帮助?通常跟踪
WebView
的旧版本(最新版本或第一个版本),以便您可以在需要时获取其信息
func updateUIView(_ uiView: WKWebView, context: Context) {
let lastURL = context.coordinator.parent.url
print(lastURL)
context.coordinator.parent = self // (*)
}
/// be cause of (*), next time lastURL will be the previous URL
/// without (*), lastURL always be the first URL you used to init WKWebView
这是另一个小示例,您可以在预览中看到
UIViewRepresentable
的工作原理
struct LabelView: UIViewRepresentable {
var text: String
func makeUIView(context: Context) -> UILabel {
let label = UILabel(frame: .init(x: 0, y: 0, width: 100, height: 100))
label.text = text
return label
}
func updateUIView(_ uiView: UILabel, context: Context) {
let lastLabel = context.coordinator.parent.text
uiView.text = "\(lastLabel) -> \(text)"
context.coordinator.parent = self
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, WKNavigationDelegate {
var parent: LabelView
init(_ parent: LabelView) {
self.parent = parent
}
}
}
struct TestLabelView: View {
@State private var num = 0
var body: some View {
Button { num += 1 } label: {
LabelView(text: "\(num)")
}
}
}