applicationWillHide not called - swift

I've implemented four functions at my appDelegate:
func applicationWillHide(_ notification: Notification)
func applicationWillUnhide(_ notification: Notification)
func applicationWillResignActive(_ notification: Notification)
func applicationDidBecomeActive(_ notification: Notification)
I tried to hide the app/minimize it, but none of them is getting called.
I also tried to add a observer for the notification - don't think it's needed but tried it anyway - so for example this is one of them:
NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.applicationWillUnhide(_:)), name: NSNotification.Name.NSApplicationWillUnhide, object: nil)
but still nothing.
All of this is done at the appDelegate.swift file.
(maybe needless to say, but the function applicationDidFinishLaunching which is also declared at NSApplicationDelegate is getting called)
Anyone has a clue on this?

While cleaning the project was helpful, only applicationWillResignActive and applicationDidBecomeActive were getting called.
So I ended up implementing NSWindowController that comfort to NSWindowDelegate, and there I have windowWillMiniaturize, windowWillClose and windowDidDeminiaturize

Related

How to implement viewWillAppear() instead of deprecated didChangeStatusBarOrientationNotification in this case?

I would like to ask how shall I shall use viewWillTransitionToSize:withTransitionCoordinator: instead of deprecated 'didChangeStatusBarOrientationNotification'. Even though in Xcode https://github.com/Mairoslav/8.2.MeMe.2.0.rev it seems that all works well except of this warning I am curious how to silence this warning or make use of it.
I want that when orientation changes from portrait to landscape and back and forth the constraints do adjust accordingly as done via method #objc func orientationChanged.
Still this warning in question is within the Notification where method #objc func orientationChanged is called.
I tried to silence it via using nil for name: , however with nil for name there is an error.
The code in question:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.orientationChanged), name: UIApplication.didChangeStatusBarOrientationNotification, object: nil)
}

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")
}

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.

ViewController + Storyboard setting up validation with controlTextDidChange

Trying to setup validation for a few text fields in a new (and very small) Swift Mac app. Following various other topics here on SO and a few other examples, I can still not get controlTextDidChange to propagate (to my ViewController).
E.g: How to live check a NSTextField - Swift OS X
I have read at least a dozen variations of basically that same concept. Since none of the accepted answers seem to work I am just getting more and more confused by something which is generally a fairly simple task on most platforms.
I have controlTextDidChange implemented to just call NSLog to let me know if I get anything.
AppDelegate should be part of the responder chain and should eventually handle controlTextDidChange but I see nothing there either.
Using the current Xcode I start a new project. Cocoa app, Swift, Storyboard and nothing else.
From what I can gather the below isolated example should work. In my actual app I have tried some ways of inserting the ViewController into the responder chain. Some answers I found suggested it was not always there. I also tried manually adding the ViewController as the delegate in code theTextField.delegate = self
Nothing I have done seems to get text changed to trigger any events.
Any ideas why I have so much trouble setting up this delegation?
My single textfield example app
Storyboard is about as simple as it gets:
AppDelegate
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, NSTextFieldDelegate, NSTextDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
func controlTextDidChange(notification: NSNotification) {
let object = notification.object as! NSTextField
NSLog("AppDelegate::controlTextDidChange")
NSLog("field contains: \(object.stringValue)")
}
}
ViewController
import Cocoa
class ViewController: NSViewController, NSTextFieldDelegate, NSTextDelegate {
#IBOutlet var theTextField: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
func controlTextDidChange(notification: NSNotification) {
let object = notification.object as! NSTextField
NSLog("ViewController::controlTextDidChange")
NSLog("field contains: \(object.stringValue)")
}
}
I think the samples you're following are a bit out-of-date.
Try...
override func controlTextDidChange(_ notification: Notification) {
...as the function definition for your method in your NSTextFieldDelegate.

How can I use applicationDidBecomeActive in UIViewController?

I want to reload data in UIViewController when application become active or become foreground.
I know applicationDidBecomeActive is called in AppDelegate class.
But I have to have a global variable for the UIViewController to reload its data in AppDelegate class like this code:
in AppDelegate.m
// global variable
UIViewController *viewController1;
UIViewController *viewController2;
-(void)applicationDidBecomeActive:(UIApplication *)application
{
[viewController1 reloadData];
[viewController2 reloadData];
}
But it is inconvenient especially when I have a lot of UIViewControllers.
Can I use applicationDidBecomeActive in UIViewController instead of in AppDelegate class?
Or are there better ways than having global variable for UIViewController?
I also need to use the following method from UIViewControllers:
-(void)applicationWillResignActive:(UIApplication *)application
-(void)applicationDidEnterBackground:(UIApplication *)application
-(void)applicationWillEnterForeground:(UIApplication *)application
At the time of reactivation, if you want to carry a particular thing for a view controller, you should register a notification in its viewDidLoad method.
UIApplicationDidBecomeActiveNotification will automatically notify your application and given controller, if they registered for it.
[[NSNotificationCenter defaultCenter]addObserver:self
selector:#selector(yourMethod)
name:UIApplicationDidBecomeActiveNotification
object:nil];
Here is an example of registering a notification handler in Swift (adapted from Apurv's answer above):
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(applicationDidBecomeActive(notification:)),
name: NSNotification.Name.UIApplicationDidBecomeActive,
object: nil)
}
#objc func applicationDidBecomeActive(notification: NSNotification) {
// do something
}
Update for Swift 4.2:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
}
#objc func applicationDidBecomeActive(notification: NSNotification) {
// Application is back in the foreground
print("active")
}
Swift 3:
NotificationCenter.default.addObserver(
self,
selector: #selector(applicationDidBecomeActive(_:)),
name: NSNotification.Name.UIApplicationDidBecomeActive,
object: nil)
func applicationDidBecomeActive(_ notification: NSNotification) {
// do something
}
Note: Don't forget to remove the observer
You cannot use applicationDidBecomeActive in viewController; it is not a method for that class.
However, you can use applicationDidBecomeActive method in AppDelegate to call any methods in your view controller that you feel are important upon launch. Just keep a pointer to your controller so the App Delegate can reach it.
What those methods might be in your view controller is entirely up to you and the details of your program. Maybe it means calling a custom update method in your view controller or whatever else you feel is necessary.
You could also use NSNotificationCenter as outlined here, with many system notifications available for application launch: http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIApplication_Class/Reference/Reference.html
However, relying heavily on NSNotificationCenter is in my opinion a good way for an app to be come disorganized. If you call everything from your main methods in the AppDelegate only, you can always refer to that method to know exactly what your app is doing upon launch. If instead you use NSNotificationCenter, you could have actions spread across many classes/objects and it can be harder to track down what is going on. Since you mentioned multiple controller objects, I think it is more streamlined and organized to call everything from applicationDidBecomeActive rather than register each viewcontroller for the same notification.
update for swift 5
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
}
// remove the observer
deinit {
print("Receiver teardown")
NotificationCenter.default.removeObserver(self)
}
#objc func applicationDidBecomeActive(notification: NSNotification) {
// Application is back in the foreground
print("applicationDidBecomeActive")
}
}
just Use NotificationCenter in your UIViewController :
NotificationCenter.default.addObserver(self,
selector: #selector(applicationWillResignActive),
name: UIApplication.willResignActiveNotification,
object: nil)
Thank you all for answering my question.
But I found easier way to use applicationDidBecomeActive in UIViewController.
#implementation AppDelegate
-(void)applicationDidBecomeActive:(UIApplication *)application
{
UIViewController<MyAppDelegate> *topViewController = (UIViewController<MyAppDelegate> *)navigationController.topViewController;
if ([topViewController respondsToSelector:#selector(MyApplicationDidBecomeActive)]) {
[topViewController MyApplicationDidBecomeActive];
}
}
#end
#protocol MyAppDelegate
#optional
-(void)MyApplicationDidBecomeActive;
#end