How to detect day change in Swift - swift

I want my app to act when there is a change to another day.
So, in my appDelegate, I put
func applicationSignificantTimeChange(_ application: UIApplication){
//this one fires
}
and in the ViewController that should update its content I do:
override func viewDidLoad() {
NotificationCenter.default.addObserver(self, selector: #selector(self.dayChanged(notification:)), name: Notification.Name("significantTimeChangeNotification"), object: nil)
}
and
#objc func dayChanged(notification: NSNotification){
//this one doesn't fire
}
somehow, while the func in AppDelegate is called, the observer seems to be blind for that event.
Is this syntax, or just plain misunderstanding of the mechanism?

You need to add an observer for "UIApplicationSignificantTimeChangeNotification":
NotificationCenter.default.addObserver(self, selector: #selector(dayChanged), name: UIApplicationSignificantTimeChangeNotification, object: nil)
For Swift 4.2 or later
NotificationCenter.default.addObserver(self, selector: #selector(dayChanged), name: UIApplication.significantTimeChangeNotification, object: nil)
Note: If your intent is to be notified when the day changes you can use .NSCalendarDayChanged ("NSCalendarDayChangedNotification") instead of UIApplication.significantTimeChangeNotification.
NotificationCenter.default.addObserver(self, selector: #selector(dayChanged), name: .NSCalendarDayChanged, object: nil)
And add the selector method to the view controller where you would like to monitor the day changes:
#objc func dayChanged(_ notification: Notification) {
}

Related

NotificationCenter - addObserver not called

I am trying a very simple code with NotificationCenter. But the addObserver is not getting called. Can any one of you check and let me know what i am missing. There are 2 simple class, one which post notification and another which listens to it. When i run the program, i just see "sending notification" in the console.
Thanks in advance.
Class 1:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("sending notification")
NotificationCenter.default.post(name: Notification.Name("test"), object: nil)
}
}
Class 2:
class secondvc: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("second vc")
NotificationCenter.default.addObserver(self,
selector: #selector(doThisWhenNotify(_:)),
name: Notification.Name("test"),
object: nil)
}
#objc func doThisWhenNotify(_ notification: Notification) {
print("inside notification")
}
}
If, at the time ViewController comes into existence, secondvc does not yet exist, then there is no one there to receive the posted notification and that is why you don't see the notification being received later when secondvc does come into existence.

Add observer without using selector

I need to add observes in my project, but since the manager that I work with, doesn't let me to use #objc in the functions, is there anyway that I can use this function without using #objc?
func createObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(self.updatedata(notification:)),
name: Notification.Name(rawValue: updateNotificationKey), object: nil)
}
#objc dynamic func updatedata(notification: NSNotification) {
updateDataIcon()
}
Your help will be appreciated.
You can use this with the inline block
NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: updateNotificationKey) , object: nil, queue: .main) { [weak self] notification in
// to do
}

NotifcationCenter causing a strong reference cycle - Swift 5

It appears I am getting a Strong Reference Cycle when using the NotifcationCenter.
I am using NotificationCenter to observe the Rotation of the device. (While some would argue this is not the best way to determine the device rotation, this currently seems to be my only route, as no autolayout is being used and storyboard is not being used).
deinit {} is never being called in my ViewController even if I remove the observer in viewWillDisappear and viewDidDisappear.
import UIKit
class TestVC: UIViewController {
deinit {
print("TestClass Deinit") //not being triggered ever
}
#objc private func rotationDetected(sender: Any) {
print("we rotated")
}
override func viewDidDisappear(_ animated: Bool) {
//NotificationCenter.default.removeObserver(UIDevice.orientationDidChangeNotification)
}
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(UIDevice.orientationDidChangeNotification)
//NotificationCenter.default.removeObserver(self) //also doesn't work
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification, object: nil, queue: .main, using: rotationDetected)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Any ideas as to why this is occurring and how to resolve it?
Also open to any new ideas on how to determine rotation detection else ways (no autolayout or storyboard is being used though).
To reach TestVC() I used self.navigationController?.pushViewController(TestVC(), animated: true) in the previous ViewController and to go back I use the pop.
Without the Observer present, the class will correctly deinit.
RESOLVED
Thanks to the answer marked below the Strong Reference Cycle is removed.
Simply replace NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification, object: nil, queue: .main, using: rotationDetected)
with
NotificationCenter.default.addObserver(self, selector: #selector(rotationDetected), name: UIDevice.orientationDidChangeNotification, object: nil)
This should work in viewWillDisappear:
NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)
in combination with using the following in viewWillAppear:
NotificationCenter.default.addObserver(self, selector: #selector(rotationDetected), name: UIDevice.orientationDidChangeNotification, object: nil)
your method of removing observer is incorrect, you should do like this:
class TestVC {
private var observer: Any
func viewWillAppear() {
observer = NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification, object: nil, queue: .main, using: rotationDetected)
}
func viewWillDisappear() {
NotificationCenter.default.removeObserver(observer)
}
}
to eliminate the Strong Reference Cycle, use weak in the closure.

notification center observer to check an NSTextView wont work right

I'm using a notification center observer to check an NSTextView
NotificationCenter.default.addObserver(self, selector: #selector(testest), name: NSTextView.didEndEditingNotification, object: nil)
it works but the thing is, i got two nstextview and it automaticly picks up on one
even when i specify its name in obejct?? why is that?
like this
NotificationCenter.default.addObserver(self, selector: #selector(testest), name: NSTextView.didEndEditingNotification, object: BoxText)
Update: It acutlay picks up on both of my NSTextViews how do i specify one?
If you pass nil all NSTextView in your view controller will receive the notification. Just create an IBOutlet to each NSTextView, cast the notification object to NSTextView and check if it is equal to each of them. If you would like to have a selector to fire just for a certain text view you need to pass it as the object parameter:
import Cocoa
class ViewController: NSViewController {
#IBOutlet var textViewLeft: NSTextView!
#IBOutlet var textViewRight: NSTextView!
override func viewDidLoad() {
super.viewDidLoad()
// If you pass nil all NSTextView in your view controller will receive the notification
NotificationCenter.default.addObserver(self, selector: #selector(didEndEditing), name: NSTextView.didEndEditingNotification, object: nil)
// If you would like to have a selector to fire just for a certain text view you need to pass it as the object parameter
NotificationCenter.default.addObserver(self, selector: #selector(didEndEditingTextViewLeft), name: NSTextView.didEndEditingNotification, object: textViewLeft)
NotificationCenter.default.addObserver(self, selector: #selector(didEndEditingTextViewRight), name: NSTextView.didEndEditingNotification, object: textViewRight)
}
#objc func didEndEditing(_ obj: Notification) {
if (obj.object as? NSTextView) == textViewLeft {
print(#function, "textViewLeft")
} else if (obj.object as? NSTextView) == textViewRight {
print(#function,"textViewRight")
}
}
#objc func didEndEditingTextViewLeft(_ obj: Notification) {
print(#function)
}
#objc func didEndEditingTextViewRight(_ obj: Notification) {
print(#function)
}
}

NsNotificationCenter is not working

Actually i'm new in swift i got stuck here,Anyone can solve this Problem. actOnSpecialNotification Func is not calling on fireNotification in ViewController.swift
In ViewController.swift
func fireNotification() -> Void {
NotificationCenter.default.addObserver(self, selector:
#selector(vikas.updateNotificationSentLabel), name:
NSNotification.Name(rawValue: mySpecialNotificationKey), object: nil)
}
func updateNotificationSentLabel() {
print("sent")
}
in SecondVC.swift
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector:
#selector(ViewController.actOnSpecialNotification), name:
NSNotification.Name(rawValue: mySpecialNotificationKey), object: nil)
}
func actOnSpecialNotification() {
print("listen")
}
First of all add Observer to your FirstViewConroller.
FirstViewConroller
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(_:)), name:”test”, object: nil)
Now, add the relevant selector method in same ViewController which will be called once the notification will be fired.
func methodOfReceivedNotification(notification: Notification){
//Take Action on Notification
}
Now, you can fire the notification using below lines which will call the above method which resides in FirstViewController
SecondViewController
NSNotificationCenter.defaultCenter().postNotificationName(“test”, object: nil)