I am implementing my first iOS Application with SwiftUI, in which I want users to be able of clicking on an invitation link for joining a topic group (DeepLinking). Like joining a WhatsApp-Group with a link.
Therefore I associated my Domain (lets say: https://invite.example.com/) with my Swift-Project.
Whenever I click/open a URL (e.g. https://invite.example.com/313bceff-58e7-40ae-a1bd-b67be466ef72) my app opens and if the user is logged in an the .onOpenURL
action method is triggered as expected.
However, if I try to save the url in a @State
URL property in the called closure, it gets not stored.
The @State
boolean property for showing the sheet is set to true
though.
That is my code in the @main struct.
import SwiftUI
@main
struct MyApp: App {
@StateObject private var appRouter: AppRouter = AppRouter()
@State private var openAcceptInvitationSheet: Bool = false
@State private var invitationURL: URL? = nil
var body: some Scene {
WindowGroup {
switch appRouter.currentScreen {
case .launch:
EmptyView()
case .login:
LoginSignupNavigationView()
case let .home(authenticatedUser):
HomeTabView()
.environmentObject(authenticatedUser)
.onOpenURL { url in
invitationURL = url //Gets not set -> url is not nil here!
openAcceptInvitationSheet = true //Is working and sheet will be presented
}
.sheet(isPresented: $openAcceptInvitationSheet) {
//invitationURL is nil -> Why?
AcceptInvitationNavigationView(invitationURL: invitationURL!)
}
}
}
}
}
Everything else is working here as expected. I guess I have a misconception of how the @State
properties work. However in all my other views I managed assigning values to @State
properties in closures which later can be used.
CodePudding user response:
Rather than using two variables for your sheet, use one – the optional URL.
.sheet(item: $invitationURL) { url in
AcceptInvitationNavigationView(invitationURL: url)
}
The optionality of your URL?
state variable takes the place of the boolean value in determining whether the sheet should display, and the sheet receives the unwrapped URL
value.
I don't think that your URL is not being set – it's more a question of it's not set at the time the original sheet's closure is evaluated, which is a subtly different SwiftUI object life cycle thing! Sticking to a single object massively simplifies everything. You'll also be able to change your code in AcceptInvitationNavigationView
to expect a URL
rather than having to deal with being passed an optional URL.
As noted in comments, this only works if URL
conforms to Identifiable
, which it doesn't by default. But you can use a URL's hashValue
to synthesize a unique identifier:
extension URL: Identifiable {
var id: Int { hashValue }
}