I've this code, what ever I try it will be "internal" ('SafariView' initializer is inaccessible due to 'internal' protection level)
@available(iOS 14.0, *)
public struct SafariView: UIViewControllerRepresentable {
public typealias UIViewControllerType = SFSafariViewController
@Binding public var urlString: String
public func makeUIViewController(
context: UIViewControllerRepresentableContext<SafariView>
) -> SFSafariViewController {
guard let url = URL(string: urlString) else {
fatalError("Invalid urlString: \(urlString)")
}
let safariViewController = SFSafariViewController(url: url)
safariViewController.preferredControlTintColor = UIColor(Color.accentColor)
safariViewController.dismissButtonStyle = .close
return safariViewController
}
public func updateUIViewController(
_ safariViewController: SFSafariViewController,
context: UIViewControllerRepresentableContext<SafariView>
) {
return
}
}
if I try to add a initializer (public init() { }), this should not work.
I get this error: Return from initializer without initializing all stored properties
if I try to add with parameters: public init(s: String) { urlString = s }
then I get this error 'self' used before all stored properties are initialized
Firstly, it doesn't seem like you need a @Binding like you have now — bindings are really meant for if you need to give another view (or simply part of your code) the ability to modify, not just read, a piece of view state.
Since reading is all you're doing here, you can change
@Binding public var urlString: String
to regular @State:
@State public let urlString: String
Secondly (as you've noticed) if you want your initializer to be publicly available you'll need to define one explicitly;
public init(urlString: String) {
self.urlString = urlString
}
Without knowing more about how you've implemented the popover's presentation, there doesn't seem to be any reason you should need a Binding here specifically. You should be able to use regular State. (There's nothing in your SafariView implementation right now that takes advantage of a Binding anyway — it won't react to urlString changing, or change it itself.)
It sounds like you may be wanting to change the URL loaded by an existing and already presentedSFSafariViewController. If that's the case you can't do that with SFSafariViewController, it's designed so that you can only decide what's initially loaded, not change it later. If you want to load a different URL you'll need to essentially destroy the existing SFSafariViewController and create a new one.
If that is what you want though, the answer may be to tell SwiftUI "destroy and recreate this view controller if urlString changes" by using something like:
SafariView(urlString: urlString)
.id(urlString)
I'm assuming that .popover is compatible with this kind of view change, it may not be, in which case you may need to adjust how you're presenting your .popover().