Hi.
I am very new to SwiftUI and still trying to learn.
I just encountered a very weird problem that I can't figure out. I have an iPad application that runs on Apple Silicon Macs as "Designed for iPad"; for some reason, this issue only comes up when running it on a Mac, even if the code is exactly the same.
This is the view that's causing issues:
struct ProfileEditView: View {
@EnvironmentObject var mainModel: MainViewModel
@EnvironmentObject var authModel: AuthViewModel
[some other stuff]
var body: some View {
GeometryReader { geo in
VStack(spacing: 20) {
navigationBar()
.padding(.horizontal, 3)
if authModel.user != nil {
VStack(alignment: .leading, spacing: 30) {
PhotosPicker(selection: self.$imageSelection,
matching: .images,
preferredItemEncoding: .compatible) {
ProfilePicView(editIconShown: true)
}
.disabled(authModel.profilePicIsLoading)
.padding(.horizontal, geo.size.width * 0.3)
.padding(.bottom)
VStack(spacing: 10) {
if let error = self.error {
Text(error)
.foregroundStyle(Color.red)
.font(.footnote)
.italic()
}
SettingsTextFieldView(String(localized: "Your name:"),
value: self.$name) {
if nameIsValid {
authModel.updateName(self.name)
}
}
}
Spacer()
actions()
}
.padding(.horizontal, 5)
.padding(.top)
.onAppear {
self.name = authModel.user!.name
}
}
}
.padding()
}
}
}
Obviously, I am injecting the ViewModels instances at the app entry point:
@main
struct MyApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
@StateObject var authViewModel: AuthViewModel = AuthViewModel()
@StateObject var mainViewModel: MainViewModel = MainViewModel()
@StateObject var statsViewModel: StatsViewModel = StatsViewModel()
@StateObject var purchaseViewModel: PurchaseViewModel = PurchaseViewModel()
@State var revenueCatIsConfigured: Bool = false
init() {
// MARK: Firebase configuration
FirebaseConfiguration.shared.setLoggerLevel(.min)
FirebaseApp.configure()
// MARK: RevenueCat configuration
if let uid = AuthViewModel.getLoggedInUserID() {
Purchases.logLevel = .error
Purchases.configure(withAPIKey: "redacted", appUserID: uid)
self.revenueCatIsConfigured = true
}
}
var body: some Scene {
WindowGroup {
MainView()
.environmentObject(authViewModel)
.environmentObject(mainViewModel)
.environmentObject(statsViewModel)
.environmentObject(purchaseViewModel)
}
}
}
And lastly, ProfileEditView that is causing issues, is a subview of MainView:
MainView has a switch statement, based on the selected tab; one of the possible views is SettingsView, which can show ProfileEditView as a sheet modifier.
For some reason, only when running on mac, I get the error
Thread 1: Fatal error: No ObservableObject of type AuthViewModel found. A View.environmentObject(_:) for AuthViewModel may be missing as an ancestor of this view.
This will come up every time I reference authModel in this view alone.
Both the iPad and iPhone versions work just fine, and again, the code is exactly the same, since it's a "Designed for iPad".
I don't even know how to troubleshoot the issue.
For some reason, passing again the view model instance from the parent view works:
struct SettingsView: View {
@EnvironmentObject var mainModel: MainViewModel
@EnvironmentObject var authModel: AuthViewModel
@EnvironmentObject var purchaseModel: PurchaseViewModel
[some stuff]
var body: some View {
GeometryReader { geo in
[some stuff]
}
.sheet(isPresented: self.$isProfileEditPresented) {
ProfileEditView(isPresented: self.$isProfileEditPresented)
.environmentObject(authModel)
}
}
}
I don't see why this is necessary, since ProfileEditView is a child View to SettingsView, and therefore should already have access to the environment object, but passing it again solved the problem.