英文:
Is it possible to check CoreData value before the app starts and show view based on the value in SwiftUI Project?
问题
The app我正在开发有两个视图,登录视图和主页视图。当应用程序第一次启动时,它会从登录视图开始。用户必须注册并输入姓名和ID,然后点击"下一步"按钮,这将导航用户到主页视图。当用户使用姓名和ID注册时,数据将保存到CoreData
中。一旦用户注册,每次用户启动应用程序时,我希望应用程序从主页视图开始。
import SwiftUI
@main
struct BJITXpressApp: App {
let persistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
if checkForRegistrationData() {
HomeView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
} else {
LoginView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
}
}
}
}
在应用程序启动时,应用程序将检查CoreData
中的注册数据,如果找到数据,应用程序将从主页视图开始。
我在Login View中使用了以下策略.onAppear
:
struct LoginView: View {
@Environment(\.managedObjectContext) var context
@State private var name: String = ""
@State private var employeeId: String = ""
@State var isShowingHomeView = false
var body: some View {
NavigationView {
// ... your LoginView content ...
}
.onAppear {
checkFirstUse()
}
.fullScreenCover(isPresented: $isShowingHomeView) {
HomeView()
}
}
}
但是这种方式会导致应用程序首先从登录视图开始,然后如果在CoreData
中找到数据,才导航到HomeView。而我想要的是应用程序从开始就检查CoreData
,然后直接导航到HomeView。
英文:
The app I am working has two view, Login View and Home View. When the app starts for the first time, it starts with the Login View. User have to register with name and id and click next button, which will navigate the user to the Home View. When the user register with the name and id the data get saved into the CoreData
.
Once the user register, every next time user starts the app I want the app starts with the Home View.
import SwiftUI
@main
struct BJITXpressApp: App {
let persistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
LoginView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
}
}
}
At the starting of the app, the app will check for registration data from CoreData
and if data is found the app will starts from Home View .
I have tried the following strategy on Login View .onAppear
struct LoginView: View {
@Environment(\.managedObjectContext) var context
@State private var name: String = ""
@State private var employeeId: String = ""
@State var isShowingHomeView = false
var body: some View {
NavigationView{...}
.onAppear{
checkFirstUse()
}
.fullScreenCover(isPresented: $isShowingHomeView){
HomeView()
}
But this way the app first starts with Login View and then if it found data in Coredata
the navigate to the HomeView.
Instead of Starts -> LoginView -> Check CoreData -> Home View , I want it like Starts -> Check CoreData -> HomeView
答案1
得分: 1
Loading Core Data is both asynchronous and possibly error-producing. You must provide some UI for the period between when the UI shows and Core Data becomes available. You must not block the UI waiting for Core Data to complete loading. It can take arbitrarily long.
Your current approach is close: Starts -> LoginView -> Check CoreData -> Home View. But instead, what you need is Starts -> LoadingView -> Check CoreData -> HomeView|LoginView.
You need to create a new LoadingView. It could be blank. The more common thing to do is to show a progress indicator. But it has to be something because there is such a state, and you have to display something in every possible state.
In one of my projects, I use the following approach to a LoadingView:
struct LoadingView<Content: View, Model>: View {
enum LoadState {
case loading
case loaded(Model)
case error(Error)
}
@ViewBuilder let content: (Model) -> Content
let loader: () async throws -> Model
@State var loadState = LoadState.loading
var body: some View {
ZStack {
Color.white
switch loadState {
case .loading: Text("Loading")
case .loaded(let model): content(model)
case .error(let error): Text(verbatim: "Error: \(error)")
}
}
.task {
do {
loadState = .loaded(try await loader())
} catch {
loadState = .error(error)
}
}
}
}
Where I have Text
, you would probably want something more professional (this comes out of a personal hobby project).
In this project, I then have Views like:
struct DailyView: View {
var body: some View {
LoadingView() { model in
LoadedDailyView(model: model)
} loader: {
try await DailyModel()
}
}
}
So the actual View always requires a Model, and it gets it as soon as the loader completes. This is far from the only approach. You can use something like you currently have. It's just an approach that I've used for inspiration.
英文:
Loading Core Data is both asynchronous and possibly error-producing. You must provide some UI for the period between when the UI shows and Core Data becomes available. You must not block the UI waiting for Core Data to complete loading. It can take arbitrarily long.
Your current approach is close: Starts -> LoginView -> Check CoreData -> Home View. But instead, what you need is Starts -> LoadingView -> Check CoreData -> HomeView|LoginView.
You need to create a new LoadingView. It could be blank. The more common thing to do is to show a progress indicator. But it has to be something because there is such a state, and you have to display something in every possible state.
In one of my projects, I use the following approach to a LoadingView:
struct LoadingView<Content: View, Model>: View {
enum LoadState {
case loading
case loaded(Model)
case error(Error)
}
@ViewBuilder let content: (Model) -> Content
let loader: () async throws -> Model
@State var loadState = LoadState.loading
var body: some View {
ZStack {
Color.white
switch loadState {
case .loading: Text("Loading")
case .loaded(let model): content(model)
case .error(let error): Text(verbatim: "Error: \(error)")
}
}
.task {
do {
loadState = .loaded(try await loader())
} catch {
loadState = .error(error)
}
}
}
}
Where I have Text
, you would probably want something more professional (this comes out of a personal hobby project).
In this project, I then have Views like:
struct DailyView: View {
var body: some View {
LoadingView() { model in
LoadedDailyView(model: model)
} loader: {
try await DailyModel()
}
}
}
So the actual View always requires a Model, and it gets it as soon as the loader completes. This is far from the only approach. You can use something like you currently have. It's just an approach that I've used for inspiration.
答案2
得分: 0
以下是代码的中文翻译:
通过以下方式解决了问题:
enum 登录状态 {
case 正在检查
case 已登录
case 未登录
case 周末
}
class 视图选择器: ObservableObject {
@Published var 登录状态: 登录状态 = .正在检查
init() {
let 是周末 = 是星期日或星期一()
if 是周末 {
登录状态 = .周末
} else {
let 已登录 =
持久性控制器.shared.是否有注册数据可用()
登录状态 = 已登录 ? .已登录 : .未登录
}
}
}
struct BJITXpressApp: App {
let 持久性控制器 = 持久性控制器.shared
@StateObject var 视图模型 = 视图选择器()
var body: some Scene {
WindowGroup {
Group {
if 视图模型.登录状态 == .正在检查 {
// 在检查登录状态时显示加载视图或其他适当的视图
Text("检查中...")
} else if 视图模型.登录状态 == .周末 {
周末视图()
} else if 视图模型.登录状态 == .已登录 {
主页视图()
.environment(\.managedObjectContext, 持久性控制器.container.viewContext)
} else if 视图模型.登录状态 == .未登录 {
登录视图()
.environment(\.managedObjectContext, 持久性控制器.container.viewContext)
}
}
}
}
}
请注意,我已将英文代码中的枚举和类名翻译成了中文,并将函数名和变量名保留为英文,以保持代码的可读性。如果您有任何其他问题或需要进一步的翻译,请随时告诉我。
英文:
Solved the issue by doing the folowing
enum LoginState {
case isChecking
case isLoggedIn
case isNotLoggedIn
case isWeekend
}
class ViewSelector: ObservableObject {
@Published var loginState: LoginState = .isChecking
init() {
let isWeekend = isSundayOrMonday()
if isWeekend{
loginState = .isWeekend
}else {
let isLoggedIn =
PersistenceController.shared.isRegisterDataAvailable()
loginState = isLoggedIn ? .isLoggedIn : .isNotLoggedIn
}
}
struct BJITXpressApp: App {
let persistenceController = PersistenceController.shared
@StateObject var viewModel = ViewSelector()
var body: some Scene {
WindowGroup {
Group {
if viewModel.loginState == .isChecking {
// Show a loading view or any other appropriate view while checking the login state
Text("Checking...")
} else if viewModel.loginState == .isWeekend{
WeekendView()
} else if viewModel.loginState == .isLoggedIn {
HomeView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
} else if viewModel.loginState == .isNotLoggedIn {
LoginView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
}
}
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论