Responding to EKEventStore Change in SwiftUI - swift

According to the Apple Developer Documentation:
An EKEventStore object posts an EKEventStoreChanged notification whenever it detects changes to the Calendar database
The article then goes on to provide examples of how to do this in UIKit:
NotificationCenter.default.addObserver(self, selector: Selector("storeChanged:"), name: .EKEventStoreChanged, object: eventStore)
In SwiftUI, I tried to do it this way:
let publisher = NotificationCenter.default.publisher(for: NSNotification.Name("EKEventStoreChanged"))
and
.onReceive(publisher) { value in
print("Store Changed")
}
But I never received any notification, and therefore the print statement was never called.
I also tried this:
let publisher = NotificationCenter.default.publisher(for: NSNotification.Name.EKEventStoreChanged)
but nothing changed.
My Question: How do I receive the EKEventStoreChanged notification in SwiftUI?
Any help would be appreciated.

Related

Setting Observer for Swift Objects/Properties

I've been looking for a way to trigger a method when the number of displays connected to a mac changes. I know I can get the value of NSScreen.screens.count, but I need to find a way to create a notification or something when that value changes or something else that would indicate a change in the number of displays connected.
I have tried KVO examples here and here, but in order for either of those to work there needs to be an event that triggers the methods inside the class.
In essence this is what I would like to do based on the first link:
class EventObserverDemo {
var statusObserver: NSKeyValueObservation?
var objectToObserve: NSScreen.screens.count?
func registerAddObserver() -> Void {
statusObserver = objectToObserve?.observe(NSScreen.screens.count, options: [.new, .old], changeHandler: {[weak self] (NSScreen.screens.count, change) in
if let value = change.newValue {
// observed changed value and do the task here on change.
print("The display count has changed.")
}
})
}
func unregisterObserver() -> Void {
if let sObserver = statusObserver {
sObserver.invalidate()
statusObserver = nil
}
}
}
I tried using a notification that used NSScreen.colorSpaceDidChangeNotification but that does not trigger a notification if a display is disconnected.
I would like to find a way to detect any time an external display is connected or disconnected. There has to be something I haven't found yet because whenever I plug in an external display to my mac I see the screen on the main display change, so there's some kind of notification that something changed whether I plug in a display or unplug it from my mac.
I looked at the didSet function, but I couldn't figure out a way to implement that on NSScreen.screens.count property.
I also looked into a property wrapper for NSScreen.screens.count but again I couldn't figure that out either.
You can observe the NSApplication.didChangeScreenParametersNotification notification. This example will only print once each time a display is either connected or disconnected, and what the change was in the number of screens.
Code:
class EventObserverDemo {
var lastCount = NSScreen.screens.count
init() {
NotificationCenter.default.addObserver(
self,
selector: #selector(trigger),
name: NSApplication.didChangeScreenParametersNotification,
object: nil
)
}
#objc private func trigger(notification: NSNotification) {
let newCount = NSScreen.screens.count
if newCount != lastCount {
print("Switched from \(lastCount) to \(newCount) displays")
lastCount = newCount
}
}
}
You don't need to remove/invalidate the observer either, easier to let the system handle it:
If your app targets iOS 9.0 and later or macOS 10.11 and later, you do not need to unregister an observer that you created with this function. If you forget or are unable to remove an observer, the system cleans up the next time it would have posted to it.

Selector function not being entered when observer is added

In my first view controller, I post the notification with the following code:
NotificationCenter.default.post(name: Notification.Name("date"), object: formattedDate)
I then "receive" the notification in a second view controller with the following code:
func receiveNotification () {
NotificationCenter.default.addObserver(self, selector: #selector(self.didGetTheDate(_:)), name: NSNotification.Name("date"), object: nil)
}
#objc
func didGetTheDate(_ notification: Notification) {
print("In did get date")
date = notification.object as! String
}
However, the function "didGetTheDate" never gets called.
I have triple checked that the function "receiveNotification" gets called as I have added print statements to check this.
Can somebody please help me with this.
NSNotificacionCenter is a variation of the Observer Pattern, you can read about it here
This means that you will have to register an Observer before posting any notification. If you post anything before that, the NSNotificationCenter will look at the observer for name and will see that nobody is listening for it, thus nothing will happen.

macOS Swift 3 - Handling notification alert action button

I'm new to Swift (but not to programming). I have simple app that provides an alert based on specific conditionals. I would like to execute a function (or even just set a variable) when one of the buttons is pressed. Ideally, I just need one button, but if for whatever reason, only the notification.actionButtonTitle can have a handler, that's fine with me.
My notification code is currently in a Swift file as a helper.
import Foundation
class NotificationHelper {
static func sampleNotification(notification: NSUserNotification) {
let notificationCenter = NSUserNotificationCenter.default
notification.identifier = "unique-id-123"
notification.hasActionButton = true
notification.otherButtonTitle = "Close"
notification.actionButtonTitle = "Show"
notification.title = "Hello"
notification.subtitle = "How are you?"
notification.informativeText = "This is a test"
notificationCenter.deliver(notification)
}
}
Currently in AppDelegate, this is defined:
let notification = NSUserNotification()
…and I call the notification like this:
NotificationHelper.sampleNotification(notification: notification)
The resulting notification works, as you can see in the screenshot below. However, I cannot seem to listen to the button action. I have tried adding this to the AppDelegate as well as the NotificationHelper file, but I did not have any success with it:
func userNotificationCenter(center: NSUserNotificationCenter, didActivateNotification notification: NSUserNotification) {
print("checking notification response")
}
Any idea of what I'm missing?
Thanks!
You'll need to assign something as the delegate of the NSUserNotificationCenter:
NSUserNotificationCenter.default.delegate = self
If you add this to your AppDelegate and make your AppDelegate conform to NSUserNotificationCenterDelegate:
class AppDelegate: NSObject, NSUserNotificationCenterDelegate {
}

call a specific View Controller when remotepush notification is clicked in swift

I want to show push notification in a specific view controller when tap on notification and also want to send data from notification to view controller. I am using swift for development
As #luzo pointed out, Notifications are the way to send to communicate to view controller(s) that an event has happened. The notification also has a userinfo parameter that accepts a dictionary of data you would like to send together with the notification to the view controller.
In Swift 3, add this to the tap button:
let center = NotificationCenter.default
center.post(name: Notification.Name(rawValue: "nameOfNotification"),
object: nil,
userInfo:["id":"data"])
And in the viewcontroller, register for the id of the notification and add a function reference:
let center = NotificationCenter.default
center.addObserver(forName:NSNotification.Name(rawValue: "nameOfNotification"), object:nil, queue:nil, using:notifDidConnect)
and add the function implementation:
func notifDidConnect(notification:Notification) -> Void {
guard let userInfo = notification.userInfo,
let id = userInfo["id"] as? String else {
print("error occured")
return
}
print("notification received")
}
You should implement router for your view controllers which will be listening to notification send from app delegate and he will decide what to do. This is how I would do it, might be a better solution.

Doubts in NSNotification in Swift

I am developing my very first app for iOS and not understanding notifications.
I am sending notifications as:
DefaultCenter.postNotificationName("evRodadaAtualizei", object: nil)
In another class, I have a method that observes this notification:
DefaultCenter.addObserver(self, selector: Selector("Atualizar"),
name: "evRodadaAtualizei", object: nil)
My question is:
This observer will listen any notification with that name? It is not important the class where notification was declared? In other words, is possible to have a place to put all the notifications (like a notification library), because all of them are independent of the class?
If I am understanding correctly, this is very different of the concept of events in C# or VB.Net where events belongs to classes.
Notifications in Cocoa work inter-class. It doesn't matter where the notification is created or observed.
However, note the object parameter on the postNotificationName method. If set, this should correspond to the object posting the notification. If you only want to observe notifications for a given object, set the object parameter to that object when you add the observer. e.g.
class MyObjectClass {
func doSomething() {
// Do something and then notify
DefaultCenter.postNotificationName("evRodadaAtualizei", object: self)
}
}
class MyObserverClass {
func startProcess() {
var myObject = MyObjectClass()
DefaultCenter.addObserver(self, selector: Selector("Atualizar"), name: "evRodadaAtualizei", object: myObject)
}
func Atualizar() {
}
}