I'm trying to make a multiplatform SwiftUI application that would run on iOS and macOS. On the last one, I would like the app to be visible only as a menu bar item (no Dock icon, no windows).
I decided to have two views:
MacSampleView()
which is used on a macOS status bar popover via customNSApplicationDelegate
SampleView()
for iOS and other Apple platforms via traditionalWindowGroup
scene
In my implementation of the App
I have the app delegate inside #if os(macOS)
compiler directive to use it only on macOS.
All was good until I decided to have a @StateObject var configuration
which I would like to share between platforms.
I have no trouble passing it as .environmentObject(configuration)
to SampleView()
in my WindowGroup
, but when I want to pass it to the MacSampleView()
which is created inside my NSApplicationDelegate
— I simply can't access it there.
I'm new to Apple platforms programming and it feels like I'm wrong somewhere on the conceptual level, so appreciate any help with that.
@main
struct SampleApp: App {
@StateObject var configuration = Config()
#if os(macOS)
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
#endif
var body: some Scene {
#if os(macOS)
Settings {
EmptyView()
}
#else
WindowGroup {
SampleView().environmentObject(configuration)
}
#endif
}
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// I struggle here! I want to pass `@StateObject var configuration` from the `SampleApp` to the `MacSampleView()` somehow.
// It's not possible to simply call `.environmentObject(configuration)` because `configuration` is unavailable in the delegate.
let macSampleView = MacSampleView()
let popover = NSPopover()
// ...
popover.contentViewController = NSHostingController(rootView: macSampleView)
// ...
}
}
CodePudding user response:
As your Config
is app-wide level single instance you can use shared object for both cases, like
class Config: ObservableObject {
static let shared = Config() // << this one !!
// .. other code
}
@main
struct SampleApp: App {
@StateObject var configuration = Config.shared // << here !!
#if os(macOS)
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
#endif
var body: some Scene {
#if os(macOS)
Settings {
EmptyView()
}
#else
WindowGroup {
SampleView().environmentObject(configuration)
}
#endif
}
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
let macSampleView = MacSampleView()
.environmentObject(Config.shared) // << same instance !!
let popover = NSPopover()
// ...
popover.contentViewController = NSHostingController(rootView: macSampleView)
// ...
}
}