I am building an app based on a large static database. Each time I open the app, I would like to check that its local database has been created from a JSON-encoded file. If this is not the case (i.e. the first time the app is opened), the data is decoded from the JSON-encoded file and inserted into the database.
This process takes about 10 seconds during which I would like to display a ProgressView() before the user has access to the interface (i.e. ContentView()).
EDIT - here is the solution:
class DatabaseBuilder: ObservableObject {
$Published var isBuilding = true
let database = SomeDatabase()
private func decodeJSON() async throws {
// long process to decode large JSON-encoded file
}
private func fillDatabase() async throws {
// long process to add new model objects to database
}
public func build() async throws {
if !database.isEmpty {
isBuilding = false
}
try await decodeJSON()
try await fillDatabase()
isBuilding = false
}
}
struct LargeDatabaseApp: App {
@StateObject var builder = DatabaseBuilder()
var body: some Scene {
WindowGroup {
ContentView()
.opacity(builder.isBuilding ? 0 : 1)
.overlay { if builder.isBuilding { ProgressView() } }
.task {
do {
try await builder.build()
} catch {
// handle error
}
}
}
}
CodePudding user response:
you could try something like this:
import SwiftUI
@main
struct LargeDatabaseApp: App {
@StateObject var builder = DatabaseBuilder()
var body: some Scene {
WindowGroup {
if builder.isBuilding {
ProgressView(){Label("building db", systemImage: "stopwatch")}
} else {
ContentView()
}
Spacer().frame(height: 0)
.onAppear {
if builder.database.isEmpty {
do {
try builder.build()
}
catch {
print(error)
}
}
}
}
}
}
class DatabaseBuilder: ObservableObject {
@Published var isBuilding = false
var database = ""
public func build() throws {
isBuilding = true
// builds database...
DispatchQueue.main.asyncAfter(deadline: .now() 5) {
self.isBuilding = false
}
}
}
struct ContentView: View {
var body: some View {
Text("ContentView here")
}
}
EDIT-1: you could also try using the scenePhase, like this:
@main
struct LargeDatabaseApp: App {
@Environment(\.scenePhase) private var scenePhase
@StateObject var builder = DatabaseBuilder()
var body: some Scene {
WindowGroup {
if builder.isBuilding {
ProgressView(){Label("building db", systemImage: "stopwatch")}
} else {
ContentView()
}
}
.onChange(of: scenePhase) { phase in
switch phase {
case .background:
print("time to write to your database")
break
case .active:
print("setup the database")
if builder.database.isEmpty {
do {
try builder.build()
}
catch {
print(error)
}
}
break
case .inactive:
print("inactive")
default: break
}
}
}
}
