AppDelegate.swift crashes macOS App - swift

When I try to launch my app, it simply crashes. The error it gives is unrecognized selector sent to instance 0x608000000ac0 and the error shows up at my AppDelegate.swift file on line 4. Here is the full AppDelegate.swift file:
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate { //This is where I get the error
#IBOutlet weak var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
}
How do I fix this error? Thanks in advance,
Aaronjam

After trying to fix the problem for over an hour, I deleted my target (after backing up my code, of course) and made a new one. Thanks for your help, #OverD!

Related

Action of StatusItem not working in Swift

So I am a newbie to Swift and wanted to create a simple example status bar app on MacOS.
To keep things clean I created a subclass App which is creating the status item. This class is then created in the applicationDidFinishLaunching function of the AppDelegate.swift.
But somehow nothing is printed on the console when I press the status icon. However if I copy the code in the AppDelegate file it works. Does someone know what I am doing wrong and why it is not working in the subclass?
Here is the code of my own class:
import Cocoa
class App: NSObject {
let menuBarItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
override init() {
print("created app instance");
if let button = menuBarItem.button {
button.image = NSImage(named: NSImage.Name("StatusBarButtonImage"))
button.action = #selector(test(_:))
}
}
#objc func test(_ sender: Any?) {
print("button was pressed")
}
}
and the AppDelegate:
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var appInstance: App!
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
appInstance = App()
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
}
If the button is showing up and nothing is happening when you click it, it looks to me like you need to make sure you're setting your button's target to your App instance. E.g.:
button.target = self
Otherwise the action is only followed up the responder chain.

AppDelegate#applicationDidFinishLaunching not called for Swift 4 MacOS app built from command line

So here is the full code:
main.swift
import Cocoa
let delegate = AppDelegate()
NSApplication.shared.delegate = delegate
NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
AppDelegate.swift
import Cocoa
class AppDelegate: NSObject, NSApplicationDelegate {
override init() {
Swift.print("AppDelegate.init")
super.init()
Swift.print("AppDelegate.init2")
}
func applicationDidFinishLaunching(aNotification: NSNotification) {
Swift.print("AppDelegate.applicationDidFinishLaunching")
}
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
Swift.print("AppDelegate.applicationShouldTerminateAfterLastWindowClosed")
}
}
Then I compile it with:
swiftc Sources/*
./main
It logs:
AppDelegate.init
AppDelegate.init2
But then it doesn't log anything else, so I close it with CTRL+C. Not sure why it's not reaching the applicationDidFinishLaunching method ever. Wondering if one knows of a fix for this, it seems like there is just one method that needs to be called somewhere, but I'm not sure.
I think this may be causing other issues such as NSMenu not working.
Hooray, it was just because of the format of the methods, which were silently failing I guess.
func applicationWillFinishLaunching(_ notification: Notification) {
Swift.print("AppDelegate.applicationWillFinishLaunching")
}
func applicationDidFinishLaunching(_ notification: Notification) {
Swift.print("AppDelegate.applicationDidFinishLaunching")
}

How can I get around passing in 'self' to the showWindow method?

I'm working through a cocoa application tutorial from the Big Nerd Ranch's Cocoa Programming 5th edition book (I'm in the beginning chapters). On their blog website for discussing the book, a user mentions that passing in 'self' isn't necessary and that it's covered in chapter 18. I'm very curious now though as to how this could be refactored without having to pass in 'self'. Is it possible?
This code is basically creating an instance of a custom ViewController which will need to load from the AppDelegate.
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var mainWindowController: MainWindowController?
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
let mainWindowController = MainWindowController()
//put the window of the window controller on the screen
mainWindowController.showWindow(self)
//set the property to point to the window controller
self.mainWindowController = mainWindowController
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
}
MainWindowController class if you need to see the functionality. It's very basic, its not doing much:
import Cocoa
class MainWindowController: NSWindowController {
#IBOutlet weak var textField: NSTextField!
override var windowNibName: NSNib.Name {
return NSNib.Name.init("MainWindowController")
}
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
#IBAction func generatePassword(_ sender: AnyObject) {
//Get a random string of length 8
let length = 8
let password = generateRandomString(length: length)
//tell the text field to display the string
textField.stringValue = password
}
}

Activate Application on Screen Unlock

I'm writing an application for macOS and I want it to detect when the screen is unlocked and then make itself become the active application.
I'm trying to use "com.apple.screenIsUnlocked", but it doesn't seem to work (the function doesn't even run). I also tried using NSWorkspaceDidWakeNotification where I got the function to run but the app didn't actually activate (presumably because the screen was still locked).
Here is what I currently have (I'm using Xcode 9.2 and Swift 4):
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(AppDelegate.screenDidUnlock), name: NSNotification.Name(rawValue: "com.apple.screenIsUnlocked"), object: nil)
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
#objc func screenDidUnlock() {
NSApplication.shared.activate(ignoringOtherApps: true)
print("Did Run")
}
The com.apple.screenIsUnlocked notification is posted to the DistributedNotificationCenter rather than the NSWorkspace's notificationCenter, so the observer should be added like this:
DistributedNotificationCenter.default().addObserver(self, selector: #selector(AppDelegate.screenDidUnlock), name: NSNotification.Name(rawValue: "com.apple.screenIsUnlocked"), object: nil)enter code here
I don't think apple allows you to run any application in the background.

Making a window visible over the loginwindow using "canBecomeVisibleWithoutLogin" and Swift on OS X 10.11

Hopefully someone can assist me.
I am trying to make a windowed application appear at the loginwindow on OSX 10.11, specifically at logout.
I am calling it using a logouthook script - I can see that the app is called on logout and the delay I have added to the application pauses the logout for 10 seconds but it doesn't actually display the main window.
The main window does display on login and I have tested removing the "canBecomeVisibleWithoutLogin" parameter which causes me to see errors in the system.log relating to the window not having permission to run over the loginwindow. Based on this, I believe the parameter is at least recognised.
I have looked around for examples on the web that use "canBecomeVisibleWithoutLogin" and I haven't been able to determine what step I am missing. I would appreciate any advice.
The code below is the only code I have added to the application which consists of a MainMenu.nib and a AppDelegate.swift.
I have also selected "visible at launch" and "Move to Active Space" in Xcode but this hasn't changed the behaviour at logout.
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
func applicationWillFinishLaunching(notification: NSNotification) {
self.window.canBecomeVisibleWithoutLogin = true
self.window.orderFrontRegardless()
self.window.level = Int(CGWindowLevelForKey(CGWindowLevelKey.StatusWindowLevelKey))
}
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
self.window.display()
let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 10 * Int64(NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {
//put your code which should be executed with a delay here
NSApplication.sharedApplication().terminate(self)
}
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
}
Setting the window level differently fixed it and I didn't need any other lines relating to self.window apart from self.window.level=2147483631
I am not sure of the full screen logout window level but I did try a couple of lower numbers and it still worked.
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
func applicationWillFinishLaunching(notification: NSNotification) {
}
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
self.window.level=2147483631
let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 10 * Int64(NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {
//put your code which should be executed with a delay here
NSApplication.sharedApplication().terminate(self)
}
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
}
I use this one:
window.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.maximumWindow)))
This seems to do the trick here.