您必须在编写代码时假设 SwiftUI 中 View 的初始化程序将被多次调用。
在这种情况下,您在makeUIView(context:)中编写初始化过程。
见:
https://developer.apple.com/documentation/swiftui/uiviewrepresentable/makeuiview(context:)
比如我基于this answer写了如下代码。我在这个引用的代码中添加了一个切换高度按钮。
-----> makeUIView 日志只输出一次,
但每次按下切换按钮时都会输出-----> webview init 日志。
import SwiftUI
import WebKit
struct ContentView: View {
var body: some View {
MyWebView()
}
}
class WebViewModel: ObservableObject {
@Published var title = ""
}
struct WebView: UIViewRepresentable {
let wkWebView = WKWebView()
init(viewModel: WebViewModel) {
print("\n-----> webview init")
}
func makeUIView(context: UIViewRepresentableContext<WebView>) -> WKWebView {
print("\n-----> makeUIView")
if let url = URL(string: "https://www.google.com") {
let request = URLRequest(url: url, cachePolicy: .returnCacheDataElseLoad)
wkWebView.load(request)
}
return wkWebView
}
func updateUIView(_ webview: WKWebView, context: UIViewRepresentableContext<WebView>) { }
}
struct MyWebView: View {
@State private var toggleHight = false
@ObservedObject private var viewModel = WebViewModel()
init() {
print("\n-----> root init")
}
var body: some View {
VStack {
WebView(
viewModel: viewModel
)
.frame(
height: { toggleHight ? 600 : 300 }()
)
Button(
"toggle",
action: {
toggleHight.toggle()
}
)
}
}
}
此外,我在编写示例代码后意识到WebView: UIViewRepresentable 不应该有wkWebView 的实例变量。
请在makeUIView(context:) 中完成所有操作(创建实例和配置),如下所示。
这是因为每次调用初始化程序时都会重新创建实例变量。
import SwiftUI
import WebKit
struct ContentView: View {
var body: some View {
MyWebView()
}
}
class WebViewModel: ObservableObject {
@Published var title = ""
}
struct WebView: UIViewRepresentable {
init(viewModel: WebViewModel) {
print("\n-----> webview init")
}
func makeUIView(context: UIViewRepresentableContext<WebView>) -> WKWebView {
print("\n-----> makeUIView")
let wkWebView = WKWebView()
if let url = URL(string: "https://www.google.com") {
let request = URLRequest(url: url, cachePolicy: .returnCacheDataElseLoad)
wkWebView.load(request)
}
return wkWebView
}
func updateUIView(_ webview: WKWebView, context: UIViewRepresentableContext<WebView>) { }
}
struct MyWebView: View {
@State private var toggleHight = false
@ObservedObject private var viewModel = WebViewModel()
init() {
print("\n-----> root init")
}
var body: some View {
VStack {
WebView(
viewModel: viewModel
)
.frame(
height: { toggleHight ? 600 : 300 }()
)
Button(
"toggle",
action: {
toggleHight.toggle()
}
)
}
}
}
当我使用UIViewControllerRepresentable 进行开发时,我一直在与这种严格的约束作斗争。在同事的帮助下,我完成了代码。
您的代码已被调用 6 次,因此可能存在一些问题。但我无法从您提供的代码中看出问题所在。
init 在SwiftUI 中被多次调用是很常见的。我们需要编写代码来处理这个问题。如果您的init 被频繁调用,您可能需要寻找根本原因。我引用的代码和我写的代码在启动时只有一次。