I am building a SwiftUI application with a list of products, where each product has an associated URL. When the user clicks the “Info” button of a product, a SafariView should open to display the corresponding URL. However, I am encountering an issue where the SafariView fails to load the correct URL the first time a product is selected. After selecting a different product, the functionality starts working as expected for all subsequent selections.
My variables:
@StateObject private var dataProvider = DataProvider()
// For INFO-Button:
@State private var safariURL: URL? = nil
@State private var showSafariView: Bool = false
ForEach(dataProvider.products) { product in
VStack(alignment: .leading) {
// "Info" Button
Button(action: {
if let urlString = product.productUrl, let url = URL(string: urlString) {
safariURL = url
print("Safari URL set: \(url); \(String(describing: safariURL))")
showSafariView = true
} else {
print("Err. 1: No valid URL available.")
safariURL = nil
showSafariView = false
}
}) {
HStack {
Text("INFO")
}
.frame(width: 120, height: 10)
.padding()
}
.background(Color.blueGradient)
.foregroundColor(.white)
// SafariView Overlay
.sheet(isPresented: $showSafariView) {
// Check, whether the URL was set
if let safariURL = safariURL {
SafariView(url: safariURL)
} else {
Text("Err. 2: No valid URL to display.")
Text("Product URL: \(String(describing: product.productUrl))")
Text("safariURL: \(String(describing: safariURL))")
}
}
struct SafariView: View {
var url: URL
var body: some View {
SafariViewController(url: url)
.edgesIgnoringSafeArea(.all)
}
}
struct SafariViewController: UIViewControllerRepresentable {
var url: URL
func makeUIViewController(context: Context) -> SFSafariViewController {
let safariVC = SFSafariViewController(url: url)
return safariVC
}
func updateUIViewController(_ uiViewController: SFSafariViewController, context: Context) {
// maybe I have to fix sth. here?
}
}
It works perfectly in Preview (xCode 16.1). In the Simulator (and TestFlight on iPhone), however, the following happens:
Lets say I get 3 products listed:
I click on the first product (or any other product):
I click on the first/same product again (no matter how many times):
Now I click on another product, e.g., the third one:
If I now go back and click on the first product again:
If I click on a product without a URL (e.g., the second one):
So, this issue only happens with the very first product I select, regardless of which product it is. The same happens when I start with the 3rd product or the 2nd. It doesn’t seem to be related to the product or the URL itself; it just doesn’t seem to “get it” the first time.
I tried so many things, e.g. to force set the URL, I tried to put a delay in opening the SafariView,.... I asked chatGPT like 100 times...
I just want the safariView to open with the correct URL immediately. If you need further information or code related to my problem, just let me know.
This is a SwiftUI quirk. Because you're not using safariURL
directly in the body of your view, SwiftUI doesn't re-evaluate the body when that variable changes. If you capture safariURL
in the sheet closure, it will work as expected. Like this:
.sheet(isPresented: $showSafariView) { [safariURL] in
// your code
}