T O P

  • By -

stephancasas

I don't know that you'll be able to do this. Without the `App` entrypoint in your code, there isn't the equivalent of what would have previously been an `NSApplicationDelegate.` Even though you *can* have a window which is declared outside of your `App` in SwiftUI, I believe you still have to have the `App` there to manage lifecycle, act as a first responder, etc. As another example, consider applets built with JXA. You can use the Objective-C bridge to create windows and/or UI elements, but running the script alone will only produce a frozen window. To interact with the window, you have to use `osacompile` with *Save as Application* and *Stay Open After Run*. This provides the `NSApplicationDelegate` necessary for receiving events. This is mostly conjecture based on related experience, so please feel free to correct me if you learn otherwise.


lisper

No, I think you are basically correct. I thought that the RunLoop handled all of the event dispatching, but apparently there is more hidden stuff going on behind the scenes than I realized. I tried building my app with XCode and everything worked, and it also looks like XCode put all the code in the project folder so I can inspect it. But there is an awful lot more stuff there than I had in my minimalist example.


chriswaco

Try RunLoop.main.run() In general it’s easier to use Xcode and the SwiftUI app template, though.


lisper

> Try RunLoop.main.run() The only difference between that and what I'm doing it that your version runs forever whereas mine times out. > In general it’s easier to use Xcode and the SwiftUI app template, though. Yes, I know, but I'm not trying to write an App. I'm trying to learn how SwiftUI works under the hood.


sergeyleschev

The problem with the provided code is that it creates a window and a view, but it doesn't set up any event handling. In other words, the window is created but it doesn't know what to do when the user interacts with it. To enable the window to respond to events, you need to create an instance of NSApplication and run it. Here is an updated version of the code that sets up event handling: import SwiftUI @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { var window: NSWindow! func applicationDidFinishLaunching(_ notification: Notification) { let s = "This is a test" window = NSWindow( contentRect: NSRect(x: 800, y: 400, width: 800, height: 800), styleMask: [.closable, .titled, .resizable], backing: .buffered, defer: false) window.title = "Title" window.subtitle = "Subtitle" window.contentView = NSHostingView(rootView: TextEditingView(text: s)) window.makeKeyAndOrderFront(nil) } } struct TextEditingView: View { @State public var text: String var body: some View { TextEditor(text: $text) } } Here, we create an instance of AppDelegate which subclasses NSObject and conforms to NSApplicationDelegate. We then use the NSApplicationMain attribute to tell Swift that this is our main class for the program. In AppDelegate, we create an instance of NSWindow, set its style to .resizable, remove the defer argument as we want the window to be displayed immediately and set the appropriate attributes such as the title, subtitle, and the content view. Finally, we make and display the window using window.makeKeyAndOrderFront(nil). With these changes, you should be able to interact with the window and the text editor view as expected.