iam trying to make an small Social Media App with SwiftUI.
I creat a ObservableObject class called user and an Sign up view where the var get there value. When iam tying to show the Data in my ProfilView a Error happens.
Thread 1: Fatal error: No ObservableObject of type User found. A View.environmentObject(_:) for User may be missing as an ancestor of this view.
Home is the Main View where i switch between the views with a bar when an Button is pressed a bool change in AppInformation.
struct ProfileView: View {
@EnvironmentObject var appUser: User
@State var beschreibung: String = ""
@State var benutzername: String = ""
@State var name: String = ""
var body: some View {
init() {
benutzername = appUser.username
name = appUser.name
}
ZStack {
Rectangle()
.frame(width: 400, height: 720)
.cornerRadius(50)
.foregroundColor(.gray)
.overlay(
HStack {
Image(systemName: "person.circle")
.resizable()
.frame(width: 100, height: 100)
.onTapGesture {
print("pressed")
}
.padding(20)
.overlay(
ZStack{
Rectangle()
.frame(width: 20, height: 20)
.offset(x: 35, y: -35)
.foregroundColor(.white)
Image(systemName: "plus.circle.fill")
.resizable()
.frame(width: 30, height: 30)
.offset(x: 35, y: -35)
.foregroundColor(.blue)
}
)
VStack {
Text(benutzername)
.font(.largeTitle)
.frame(width: 240 ,alignment: .leading)
.offset(x: -10, y: -25)
.lineLimit(1)
Text(name)
.frame(width: 220, alignment: .leading)
.offset(x: -15,y: -20)
.lineLimit(1)
}
}
.frame(width: 400, height: 720, alignment: .topLeading)
)
.padding()
ZStack {
Rectangle()
.foregroundColor(.secondary)
.frame(width: 380, height: 510)
.cornerRadius(45)
}
.frame(width: 400, height: 700, alignment: .bottom)
.padding()
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
}
}
class User: ObservableObject{
@Published var username: String = ""
@Published var name: String = ""
var password: String = ""
@Published var email: String = ""
@Published var beschreibung: String = ""
}
@State var isSecured: Bool = true
@State var noPassword: Int = 0
@State var noEmail: Int = 0
@State var noUsername: Int = 0
@State var noName: Int = 0
@State var password: String = ""
@State var username: String = ""
@State var name: String = ""
@State var email: String = ""
@EnvironmentObject var appInfo: AppInformation
@EnvironmentObject var appUser: User
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 25)
.frame(width: 380, height: 650)
.overlay(Text("Erstelle Accout ")
.foregroundColor(.white)
.frame(width: 360, height: 510, alignment: .top)
.font(.headline))
ZStack {
VStack {
TextField("Username", text: $username)
.frame(width:180 ,height:40 ,alignment: .center)
.multilineTextAlignment(.center)
.font(.headline)
.background(Color.gray.opacity(0.25))
.clipShape(Capsule())
.foregroundColor(.white)
.border(.red, width: CGFloat(noUsername))
Spacer()
.frame(height: 35)
TextField("Full name", text: $name)
.frame(width:180 ,height:40 ,alignment: .center)
.multilineTextAlignment(.center)
.font(.headline)
.background(Color.gray.opacity(0.25))
.clipShape(Capsule())
.foregroundColor(.white)
.border(.red, width: CGFloat(noName))
Spacer()
.frame(height: 35)
TextField("Email", text: $email)
.frame(width:180 ,height:40 ,alignment: .center)
.multilineTextAlignment(.center)
.font(.headline)
.background(Color.gray.opacity(0.25))
.clipShape(Capsule())
.foregroundColor(.white)
.border(.red, width: CGFloat(noEmail))
Spacer()
.frame(height: 35)
HStack {
Spacer()
.frame(width: 37)
if isSecured {
SecureField("Password", text: $password)
.frame(width:180 ,height:40 ,alignment: .center)
.multilineTextAlignment(.center)
.font(.headline)
.background(Color.gray.opacity(0.25))
.clipShape(Capsule())
.foregroundColor(.white)
.border(.red, width: CGFloat(noPassword))
} else {
TextField("Password", text: $password)
.frame(width:180 ,height:40 ,alignment: .center)
.multilineTextAlignment(.center)
.font(.headline)
.background(Color.gray.opacity(0.25))
.clipShape(Capsule())
.foregroundColor(.white)
.border(.red, width: CGFloat(noPassword))
}
ZStack {
Button(" ") {
isSecured.toggle()
print(isSecured)
}
Image(systemName: self.isSecured ? "eye" : "eye.slash")
.foregroundColor(.gray)
}
}
Spacer()
.frame(height: 60)
Button("Erstellen"){
if username == "" {
noUsername = 1
if name == "" {
noName = 1
if email == "" {
noEmail = 1
if password == "" {
noPassword = 1
}
}
else if password == "" {
noPassword = 1
}
}
else if email == "" {
noEmail = 1
if password == "" {
noPassword = 1
}
}
else if password == "" {
noPassword = 1
}
}
else if name == "" {
noName = 1
if email == "" {
noEmail = 1
if password == "" {
noPassword = 1
}
}
else if password == "" {
noPassword = 1
}
}
else if email == "" {
noEmail = 1
if password == "" {
noPassword = 1
}
}
else if password == "" {
noPassword = 1
}
else {
appUser.username = username
appUser.email = email
appUser.password = password
appUser.name = name
appInfo.finished = true
}
}
.font(.headline)
.frame(width: 150, height: 50)
.background(.blue)
.foregroundColor(.white)
.clipShape(Capsule())
}
}
}
}
}
class AppInformation: ObservableObject{
@Published var home: Bool = true
@Published var camera: Bool = false
@Published var friends: Bool = false
@Published var profil: Bool = false
@Published var showBar: Bool = true
@Published var finished: Bool = false
}
struct Home: View {
@EnvironmentObject var appInfo: AppInformation
@EnvironmentObject var appUser: User
var body: some View {
ZStack {
if appInfo.finished {
if appInfo.home {
HomeView()
}
else if appInfo.camera {
MakePostView()
}
else if appInfo.friends {
FriendsView()
}
else if appInfo.profil {
ProfileView()
.environmentObject(appUser)
}
if appInfo.showBar {
NavigationBar()
}
}
else {
ErstellenView().environmentObject(appInfo)
.environmentObject(appUser)
}
}
}
}
2
Answers
User should be a struct and make it a published property on the appInfo object. We usually only have one environment object holding the model structs and we usually call it model rather than appInfo.
Most of your existing bools in appInfo should be in an @State var bool in the View struct and related ones could be together in an @State var struct and you can use mutating funcs to manipulate the data.
In
ProfileView
you must not haveinit()
inside the view body.Remove
init()
completely, and instead, useappUser.username
andappUser.name
directly, such as:Text(appUser.username)
andText(appUser.name)
. This is the purpose of using aUser
ObservableObject
model. There is no need to createlocal variables. When you try to access
appUser
ininit()
theEnvironmentObject
will not be ready, it will be...missing as an ancestor of this view
. In other words, you should not useEnvironmentObject
ininit()
.