I am a total rookie to coding, and this is my first project. I have created an app that determines the risk of CardioVascular Disease(CVD) based on the data from cholesterol panel lab tests.The app runs on the iPhone XR (canvas simulator) with no trouble. However, when i run the app on my actual iPhone XR device, it crashes and yields the following message:
Fatal Error: No ObservableObject of Type Data found. A View.environmentObject(_:) for Data
may be missing as an ancestor of this view.
Here is where the error appeared:
TextField("", text: $data.name)
.frame(width:350, height: 40)
.padding(.leading)
.background(Color.offWhite)
.foregroundColor(.fblue)
.cornerRadius(5)
.shadow(color: Color.black.opacity(0.4), radius: 5, x: 5, y: 5)
.shadow(color: Color.white.opacity(1.5), radius:5, x: -5, y: -5)
.font(.title)
.keyboardType(.alphabet)
I have searched Stack Overflow (SO) and attempted all of the recommended solutions, none of which worked for me. I also searched outside of SO and made similar attempts with similar results. I have returned to SO to see if anyone can help me. Based on this research, I think I'm having a problem with making my ObservableObject "visible" to the entire app even though I've precisely followed well-respected coders and coding gurus (SO contributors, Paul Hudson, AzamSharp, Maxcodes, Brian Advent, Code with Chris etc;) and their analogous examples during the building of my app. So, my problem is either in the syntax of the code I've used to reference the ObservableObject, or I've placed that reference code in the wrong place within the app, or there's a piece of code that I'm missing, and it was never referred to in any of my research.
The app consists of three views of user input utilizing TextFields, NavViews and NavLinks. One view showing the results of user input, and a final view showing a diagnosis and % risk of CVD. I employed @EnvironmentObject, ObservableObject, @Published var, and @State private var throughout.
Here are some code details:(only pertinent code is presented)
My Scene Delegate:
import UIKit
import SwiftUI
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene (_: UIScene, WillConnectTo session: UISceneSession, option connectingOptions:
UIScene.ConnectionOptions) {
//......
//......
let data = Data()
//....
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
// .....
// .....
let contentView = ContentView(
.environmentObject(data)
.environment(\.managedObjectContext, context)
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView.environmentObject(data))
self.window = window
window.makeKeyAndVisible()
}
}
func sceneDidDisconnect.......
My class declaration in ContentView:
class Data: ObservableObject {
@Published var name = ""
@Published var age = ""
@Published var dob = ""
@Published var gender = ""
@Published var fast = ""
@Published var tc = ""
@Published var tg = ""
@Published var hdl = ""
@Published var ldl = ""
@Published var vldl = ""
@Published var apoB = ""
@Published var apoA1 = ""
@Published var apoRatio = ""
}
My ResultsDiagnostics struct in ResultsDiagnosticsView:
struct ResultsDiagnosticsView: View {
init() {
UITableView.appearance().tableFooterView = UIView()
UITableView.appearance().separatorStyle = .none
}
@EnvironmentObject var data: Data
@State private var name = ""
@State private var age = ""
@State private var dob = ""
@State private var selectedGender = ""
@State private var tc = ""
@State private var tg = ""
@State private var hdl = ""
@State private var ldl = ""
@State private var vldl = ""
@State private var apoB = ""
@State private var apoA1 = ""
var ptDOB: Double{
let patientDOB = Double(data.dob) ?? 0
return patientDOB
}
var ptTC: Double{
let patientTC = Double(data.tc) ?? 0
return patientTC
}
var ptTG: Double{
let patientTG = Double(data.tg) ?? 0
return patientTG
}
var ptHDL: Double{
let patientHDL = Double(data.hdl) ?? 0
return patientHDL
}
var ptLDL: Double{
let patientLDL = Double(data.ldl) ?? 0
return patientLDL
}
var ptVLDL: Double{
let patientVLDL = Double(data.vldl) ?? 0
return patientVLDL
}
var ptAPOB: Double{
let patientAPOB = Double(data.apoB) ?? 0
return patientAPOB
}
var ptAPOA1: Double{
let patientAPOA1 = Double(data.apoA1) ?? 0
return patientAPOA1
}
var ptAPOBA1: Double{
let patientAPOBA1 = ptAPOB/ptAPOA1
return patientAPOBA1
}
My DiagnosticsRisk stuct DiagnosticsRiskView:
struct DiagnosticsRiskView: View {
@EnvironmentObject var data: Data
@State private var name = ""
@State private var age = ""
@State private var dob = ""
@State private var selectedGender = ""
@State private var tc = ""
@State private var tg = ""
@State private var hdl = ""
@State private var ldl = ""
@State private var vldl = ""
@State private var apoB = ""
@State private var apoA1 = ""
var ptDOB: Double{
let patientDOB = Double(data.dob) ?? 0
return patientDOB
}
var ptTC: Double{
let patientTC = Double(data.tc) ?? 0
return patientTC
}
var ptTG: Double{
let patientTG = Double(data.tg) ?? 0
return patientTG
}
var ptHDL: Double{
let patientHDL = Double(data.hdl) ?? 0
return patientHDL
}
var ptLDL: Double{
let patientLDL = Double(data.ldl) ?? 0
return patientLDL
}
var ptVLDL: Double{
let patientVLDL = Double(data.vldl) ?? 0
return patientVLDL
}
var ptAPOB: Double{
let patientAPOB = Double(data.apoB) ?? 0
return patientAPOB
}
var ptAPOA1: Double{
let patientAPOA1 = Double(data.apoA1) ?? 0
return patientAPOA1
}
var ptAPOBA1: Double{
let patientAPOBA1 = ptAPOB/ptAPOA1
return patientAPOBA1
}
func progress() -> Double {
let j = (ptAPOBA1*3.43) - 0.099
let k = (j/(1+j)) * 100
let l = Double(round(10*k)/10)
return l
}
func setProgress()->CGFloat{
let temp = self.progress() / 2
return CGFloat(temp * 0.01)
}
My NavView?NavLink for ResultsDiagnosticsView:
NavigationView {
VStack {
List{
Section(header: Text("Demographics").modifier(SectionMod())) {
HStack {
Text("Patient")
.modifier(Label())
Text(data.name)
.modifier(ResultText())
}.modifier(HStackMod())
.padding(.top, 10)
HStack {
HStack{
Text("Gender")
.modifier(Label())
Text(data.gender)
.modifier(ResultText())
}.modifier(HStackMod())
HStack{
Text("Fasting")
.modifier(Label())
Text(data.fast)
.modifier(ResultText())
}.modifier(HStackMod())
}
HStack {
Text("DOB ")
.modifier(Label())
Text(data.dob)
.modifier(ResultText())
}.modifier(HStackMod())
.padding(.bottom, 10)
}
Section(header: Text("Cholesterol/Triglycerides").modifier(SectionMod())) {
HStack{
Text("Cholesterol")
.modifier(Label())
Spacer()
.frame(width:115)
if ptTC < 200 {
Text("\(ptTC, specifier: "%.2f") N")
.modifier(Normal())
}else{
Text("\(ptTC, specifier: "%.2f") H")
.modifier(Abnormal())
}
}.modifier(HStackMod())
.padding(.top)
HStack{
Text("Triglycerides")
.modifier(Label())
Spacer()
.frame(width:115)
if ptTG < 100 {
Text("\(ptTG, specifier: "%.2f") N")
.modifier(Normal())
}else{
Text("\(ptTG, specifier: "%.2f") H")
.modifier(Abnormal())
}
}.modifier(HStackMod())
.padding(.bottom, 10)
}
Section(header: Text("Lipoproteins").modifier(SectionMod())) {
HStack{
Text("HDL")
.modifier(Label())
Spacer()
if ptHDL >= 50{
Text("\(ptHDL, specifier: "%.2f") N")
.modifier(Normal())
}else{
Text("\(ptHDL, specifier: "%.2f") L")
.modifier(Abnormal())
}
}.modifier(HStackMod())
.padding(.top, 10)
HStack{
Text("LDL")
.modifier(Label())
Spacer()
if ptLDL < 100{
Text("\(ptLDL, specifier: "%.2f") N")
.modifier(Normal())
}else{
Text("\(ptLDL, specifier: "%.2f") H")
.modifier(Abnormal())
}
}.modifier(HStackMod())
HStack{
Text("VLDL")
.modifier(Label())
Spacer()
if ptVLDL <= 30{
Text("\(ptVLDL, specifier: "%.2f") N")
.modifier(Normal())
}else{
Text("\(ptVLDL, specifier: "%.2f") H")
.modifier(Abnormal())
}
}.modifier(HStackMod())
.padding(.bottom, 10)
}
Section(header: Text("Apolipoproteins").modifier(SectionMod())) {
HStack{
Text("Apo B")
.modifier(Label())
Spacer()
if ptAPOB < 85 {
Text("\(ptAPOB, specifier: "%.2f") N")
.modifier(Normal())
}else{
Text("\(ptAPOB, specifier: "%.2f") H")
.modifier(Abnormal())
}
}.modifier(HStackMod())
.padding(.top)
HStack {
Text("Apo A1")
.modifier(Label())
Spacer()
if ptAPOA1 >= 135{
Text("\(ptAPOA1, specifier: "%.2f") N")
.modifier(Normal())
}else{
Text("\(ptAPOA1, specifier: "%.2f") L")
.modifier(Abnormal())
}
}.modifier(HStackMod())
HStack {
Text("Apo Ratio")
.modifier(Label())
Spacer()
if ptAPOBA1 < 0.63 {
Text("\(ptAPOBA1, specifier: "%.2f") N")
.modifier(Normal())
}else{
Text("\(ptAPOBA1, specifier: "%.2f ") H")
.modifier(Abnormal())
}
}.modifier(HStackMod())
}
}
HStack{
NavigationLink(destination: TCTGView().navigationBarTitle("")
.navigationBarBackButtonHidden(true)
.navigationBarHidden(true)) {
Text("Start Over")
.fontWeight(.bold)
.font(.subheadline)
.padding()
.background(Color.fblue)//
.foregroundColor(.white)
.cornerRadius(10)
.shadow(color: Color.black.opacity(0.4), radius: 5, x: 5, y: 5)
.shadow(color: Color.white.opacity(1.5), radius:5, x: -5, y: -5)
}
NavigationLink(destination: ApolipoproteinsView().navigationBarTitle("")
.navigationBarBackButtonHidden(true)
.navigationBarHidden(true)) {
Text("Back")
.fontWeight(.bold)
.font(.subheadline)
.padding()
.background(Color.fblue)
.foregroundColor(.white)
.cornerRadius(10)
.shadow(color: Color.black.opacity(0.4), radius: 5, x: 5, y: 5)
.shadow(color: Color.white.opacity(1.5), radius:5, x: -5, y: -5)
}
NavigationLink(destination: DiagnosticsRiskView().navigationBarTitle("")
.navigationBarBackButtonHidden(true)
.navigationBarHidden(true)) {
Text("Next")
.fontWeight(.bold)
.font(.subheadline)
.padding()
.background(Color.fblue)
.foregroundColor(.white)
.cornerRadius(10)
.shadow(color: Color.black.opacity(0.4), radius: 5, x: 5, y: 5)
.shadow(color: Color.white.opacity(1.5), radius:5, x: -5, y: -5)
}
}.padding(.bottom, 80)
}
}.edgesIgnoringSafeArea(.top)
If a full copy of the app would be more helpful, please email me (wcmarrocco@gmail.com), since I couldn't figure out how to embed a copy of my project here.Thank you!