Subclass Nsapplication in Swift

Subclass NSApplication in Swift

Try:

@objc(MyApplication)
class MyApplication: NSApplication {

OR, you have to set Info.plist like this.

<key>NSPrincipalClass</key>
<string>YourAppName.MyApplication</string>
^^^^^^^^^^^^

There is no exact document about this, but this description is corresponding:

In order to preserve namespacing when a Swift class is used in Objective-C code, Swift classes are exposed to the Objective-C runtime with their fully qualified names. Therefore, when you work with APIs that operate on the string representation of a Swift class, you must include the fully qualified name of the class. For example, when you create a document–based Mac app, you provide the name of your NSDocument subclass in your app’s Info.plist file. In Swift, you must use the full name of your document subclass, including the module name derived from the name of your app or framework.

and this:

When you use the @objc(<#name#>) attribute on a Swift class, the class is made available in Objective-C without any namespacing.

Sending replyToApplicationShouldTerminate to NSApplication in Swift

I believe you should change

NSApplication.replyToApplicationShouldTerminate(true)

to

NSApplication.sharedApplication().replyToApplicationShouldTerminate(true)

since replyToApplicationShouldTerminate is a instance method rather then a class method.

NSWindow not closing when created with custom NSApplication

I seem to have solved the problem, In Objective-C I can just use this, and my app will respond to the quit item in the dock menu.

NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask 
untilDate:nil
inMode:NSDefaultRunLoopMode
dequeue:YES];

In Swift if you try to get the next event like that you would do this:

let event = nextEventMatchingMask(Int(NSEventMask.AnyEventMask.rawValue),
untilDate: NSDate.distantPast(),
inMode: NSDefaultRunLoopMode,
dequeue: true)

However, you get an overflow error when converting from UInt64 to Int. This seems to be unintended. At first, I tried to resolve this problem by replacing it with 0xfffffffffffffff. This worked fine, and the app would respond to events. But this was not enough, actually. The app needs to also respond to events matching a mask 0x1. I have no idea why, but this allows me to quit and hide my app from the dock menu. (0x0 only allows me to quit.)

So then, the entire run() implementation of a Swift NSApplication subclass is this:

override func run() {
finishLaunching()
setValue(true, forKey: "running")

while true {
let event = nextEventMatchingMask(0xfffffffffffffff, untilDate: NSDate.distantPast(), inMode: NSDefaultRunLoopMode, dequeue: true)
let dockEvent = nextEventMatchingMask(0x1, untilDate: NSDate.distantPast(), inMode: NSDefaultRunLoopMode, dequeue: true)

if dockEvent != nil { sendEvent(dockEvent!) }
if event != nil { sendEvent(event!) }

if !running { break }

updateWindows()
}
}

NSApplicationDelegate not working without Storyboard

You need to do a few things here

  1. Delete NSMainStoryboardFile key/value from the plist
  2. Create a NSApplication subclass and assign it to the Principal Class (NSPrincipalClass) key.

assign custom class to principal class

The name must be fully qualified with your module name.


  1. Manually instantiate your delegate in your NSApplication subclass and assign it to the delegate property.

Make sure you keep a strong reference to your delegate object. Ive just used a let here.

class GrookApplication: NSApplication {

let strongDelegate = AppDelegate()

override init() {
super.init()
self.delegate = strongDelegate
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

}

e.g a simple delegate.

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

override init() {
super.init()
print("wassup")
//conceptual proof of life init override
//wait until applicationDidFinishLaunching , specially for UI
}

var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
print("yo! I'm alive")
window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 200, height: 200), styleMask: .titled, backing: .buffered, defer: false)
window.makeKeyAndOrderFront(nil)
}

}

EDIT 2018 Verified High Sierra

Do NOT try and do window or view controller initialisation inside init this leads to double app initialisation issues and crashing. The app has not finished launching at this stage. Wait until applicationDidFinishLaunching to fire any significant operations.

How to get Main Window (App Delegate) from other class (subclass of NSViewController)?

For the mainWindow method the docs say:

This method might return nil if the application’s nib file hasn’t finished loading, if the receiver is not active, or if the application is hidden.

I just created a quick test application and I placed the following code:

NSLog(@"%@", [[NSApplication sharedApplication] mainWindow]);

into my applicationDidFinishLaunching:aNotification method, and into an action method which I connected to a button in the main window of my application.

On startup, the mainWindow was nil, but when I click the button (after everything is up and running and displayed), the mainWindow was no longer nil.

NSApplication provides other methods which you may be useful to you:

  • - windows - an array of all the windows;
  • – keyWindow - gives the window that is receiving keyboard input (or nil);
  • – windowWithWindowNumber: - returns a window corresponding to the window number - if you know the number of the window whose contents you wish to replace you could use this;
  • – makeWindowsPerform:inOrder: - sends a message to each window - you could use this to test each window to see if it's the one you are interested in.

With regard to calling methods on the delegate, what you say gives a warning works fine for me. For example, this works with no warnings:

NSLog(@"%@", [[[NSApplication sharedApplication]delegate] description]);

What exactly is the warning you receive? Are you trying to call a method that doesn't exist?

How do I use a subclass of NSDocumentController in XCode 4?

In your application delegate:

// LukeAppDelegate.h
#import "LukeAppDelegate.h"
#import "VRDocumentController"

- (void)applicationWillFinishLaunching:(NSNotification *)notification {
VRDocumentController *dc = [[VRDocumentController alloc] init];
}

This will make sure that an instance of VRDocumentController is created and registered as the shared document controller, preventing Cocoa from using the default NSDocumentController.

As to why you haven’t been able to use a custom object in your nib file, make sure that that you select Object (blue cube) instead of Object Controller (blue cube inside a green sphere) when dragging a new object into the nib file.


Edit: If you’re targeting an OS X version that supports restoration, -applicationWillFinishLaunching: may be too late to register a custom document controller. If the application delegate is placed inside MainMenu.xib, it should be instantiated by the nib loading process before any documents are restored, hence you can move the NSDocumentController subclass initialisation to the application delegate’s init method:

// LukeAppDelegate.h
#import "LukeAppDelegate.h"
#import "VRDocumentController"

- (id)init {
self = [super init];
VRDocumentController *dc = [[VRDocumentController alloc] init];
return self;
}

NSApplication init failure: Creating more than one Application

Looking at my own code for doing without NSApplicationMain(), you don't alloc init the NSApplication instance.

You should do this-- use the sharedApplication singleton generator method:

NSApplication *application = [NSApplication sharedApplication];

See, for instance, the answer here. I also talk about a few other things that break when NSApplicationMain() isn't used.

@cacau got me squinting at that assertion. It's in the NSApplication init method you call in the very first line of the app. Does it look like the exception happens there if you set an exception breakpoint?

Hope that helps, though I expect you'll run into more issues. I haven't done the no-NSApplicationMain thing for a document based app.

For what it's worth, the sharedApplication reference says:

This method also makes a connection to the window server and completes other initialization. Your program should invoke this method as one of the first statements in main(); this invoking is done for you if you create your application with Xcode.



Related Topics



Leave a reply



Submit