基于身份验证状态的 SwiftUI 私有路由
SwiftUI private route based on Authentication Status
我需要在 swiftUI 上实现一种机制,就像反应私有和 public 路由一样。基本上我有几十个视图,其中一些视图需要根据用户登录状态进行身份验证。到目前为止,我已尝试将当前屏幕保存在环境对象中,如下所示 class
enum Routes {
case screenA,
screenB,
screenC,
screenD,
screenE,
screenF,
screenG,
loginScreen
var isAuthRequired: Bool {
if case . screenA = self {
return true
} else if case . screenD = self {
return true
} else {
return false
}
}
}
class AuthenticatedRoute: ObservableObject {
@Published var currentRoute: Routes
init(){
self.currentRoute = . screenA
}
}
在我的主屏幕上,每次当前屏幕更改时,我都会检查用户登录和当前页面是否需要身份验证。
struct MainView: View {
@StateObject var authenticatedRoute = AuthenticatedRoute()
@EnvironmentObject var userAuth: UserAuth
var body: some View {
mainView()
.environmentObject(authenticatedRoute)
}
@ViewBuilder
func mainView() -> some View {
if (self.authenticatedRoute.currentRoute.isAuthRequired && !userAuth.isLoggedIn) {
LoginView()
}
else {
DefaultTabView()
}
}
}
这是我如何不断更改此环境变量的示例。我改变了视图的环境对象onAppear事件方法。
struct ScreenA: View {
@EnvironmentObject var authenticatedRoute: AuthenticatedRoute
var body: some View {
NavigationView {
someContent()
}.onAppear {
authenticatedRoute.currentRoute = .screenA
}
}
}
虽然出于某种原因这种方法适用于大多数情况,但当屏幕处于选项卡导航时它会表现得很奇怪。此外,我对这个解决方案感到不舒服,我需要在每个页面上手动更改屏幕名称,并在主视图中检查身份验证状态。我认为如果我可以在每次页面更改之前编写一种拦截器并检查所需的目的地是否需要身份验证以及用户是否经过身份验证但我找不到管理它的方法会更好。我是 iOS 开发的新手,有过 React Native 的经验,但我认为这应该不难实现,因为这是大多数应用程序的要求。
所以基本上我需要在 swiftUI 中实现私有和 public 路由器或拦截每个页面更改,所以我不应该手动修改每个页面上的环境变量,也不应该检查函数内 MainView 中的条件。
我可以提出另一种不需要 class AuthenticatedRoute
的方法,希望这就是您要找的。过程是:
在 class UserAuth
中,创建一个静态 shared
实例,它可以在您的代码中的任何地方调用,并确保您始终使用同一个实例.
创建一个扩展View
的修饰符,读取UserAuth.shared
中的状态,并根据是否需要认证显示必要的视图(LoginView()
如果用户未通过身份验证。
在需要用户进行身份验证的任何视图的最外层容器(VStack
、NavigationView
等)使用修饰符。
下面的例子展示了它是如何工作的,如果你想 运行 它:
1.静态UserAuth
实例
class UserAuth: ObservableObject {
static let shared = UserAuth() // This is to assure that you refer to the same instance all over the code
@Published private(set) var isLoggedIn = false // Use the variable you already have
func logInOrOff() { // Implement each func as needed
isLoggedIn.toggle()
}
}
2。创建 View
修饰符
extension View {
@ViewBuilder
func requiresAuthentication() -> some View {
if UserAuth.shared.isLoggedIn { // "shared" is the same instance used by the views
self
} else {
LoginView()
}
}
}
3。在需要认证的视图底部应用修饰符
struct Example: View {
@StateObject private var userAuth = UserAuth.shared // Or @EnvironmentObject, as you wish
var body: some View {
VStack {
Text(userAuth.isLoggedIn ? "Now we're good" : "You must log in")
.padding()
Button {
userAuth.logInOrOff()
} label: {
Text("Logoff")
}
}
.requiresAuthentication() // This is what makes your view safe
}
}
struct LoginView: View {
var body: some View {
VStack {
Text("Authentication is required")
.padding()
Button {
UserAuth.shared.logInOrOff()
} label: {
Text("Log in")
}
}
}
}
我需要在 swiftUI 上实现一种机制,就像反应私有和 public 路由一样。基本上我有几十个视图,其中一些视图需要根据用户登录状态进行身份验证。到目前为止,我已尝试将当前屏幕保存在环境对象中,如下所示 class
enum Routes {
case screenA,
screenB,
screenC,
screenD,
screenE,
screenF,
screenG,
loginScreen
var isAuthRequired: Bool {
if case . screenA = self {
return true
} else if case . screenD = self {
return true
} else {
return false
}
}
}
class AuthenticatedRoute: ObservableObject {
@Published var currentRoute: Routes
init(){
self.currentRoute = . screenA
}
}
在我的主屏幕上,每次当前屏幕更改时,我都会检查用户登录和当前页面是否需要身份验证。
struct MainView: View {
@StateObject var authenticatedRoute = AuthenticatedRoute()
@EnvironmentObject var userAuth: UserAuth
var body: some View {
mainView()
.environmentObject(authenticatedRoute)
}
@ViewBuilder
func mainView() -> some View {
if (self.authenticatedRoute.currentRoute.isAuthRequired && !userAuth.isLoggedIn) {
LoginView()
}
else {
DefaultTabView()
}
}
}
这是我如何不断更改此环境变量的示例。我改变了视图的环境对象onAppear事件方法。
struct ScreenA: View {
@EnvironmentObject var authenticatedRoute: AuthenticatedRoute
var body: some View {
NavigationView {
someContent()
}.onAppear {
authenticatedRoute.currentRoute = .screenA
}
}
}
虽然出于某种原因这种方法适用于大多数情况,但当屏幕处于选项卡导航时它会表现得很奇怪。此外,我对这个解决方案感到不舒服,我需要在每个页面上手动更改屏幕名称,并在主视图中检查身份验证状态。我认为如果我可以在每次页面更改之前编写一种拦截器并检查所需的目的地是否需要身份验证以及用户是否经过身份验证但我找不到管理它的方法会更好。我是 iOS 开发的新手,有过 React Native 的经验,但我认为这应该不难实现,因为这是大多数应用程序的要求。
所以基本上我需要在 swiftUI 中实现私有和 public 路由器或拦截每个页面更改,所以我不应该手动修改每个页面上的环境变量,也不应该检查函数内 MainView 中的条件。
我可以提出另一种不需要 class AuthenticatedRoute
的方法,希望这就是您要找的。过程是:
在 class
UserAuth
中,创建一个静态shared
实例,它可以在您的代码中的任何地方调用,并确保您始终使用同一个实例.创建一个扩展
View
的修饰符,读取UserAuth.shared
中的状态,并根据是否需要认证显示必要的视图(LoginView()
如果用户未通过身份验证。在需要用户进行身份验证的任何视图的最外层容器(
VStack
、NavigationView
等)使用修饰符。
下面的例子展示了它是如何工作的,如果你想 运行 它:
1.静态UserAuth
实例
class UserAuth: ObservableObject {
static let shared = UserAuth() // This is to assure that you refer to the same instance all over the code
@Published private(set) var isLoggedIn = false // Use the variable you already have
func logInOrOff() { // Implement each func as needed
isLoggedIn.toggle()
}
}
2。创建 View
修饰符
extension View {
@ViewBuilder
func requiresAuthentication() -> some View {
if UserAuth.shared.isLoggedIn { // "shared" is the same instance used by the views
self
} else {
LoginView()
}
}
}
3。在需要认证的视图底部应用修饰符
struct Example: View {
@StateObject private var userAuth = UserAuth.shared // Or @EnvironmentObject, as you wish
var body: some View {
VStack {
Text(userAuth.isLoggedIn ? "Now we're good" : "You must log in")
.padding()
Button {
userAuth.logInOrOff()
} label: {
Text("Logoff")
}
}
.requiresAuthentication() // This is what makes your view safe
}
}
struct LoginView: View {
var body: some View {
VStack {
Text("Authentication is required")
.padding()
Button {
UserAuth.shared.logInOrOff()
} label: {
Text("Log in")
}
}
}
}