How to register Notification Center in class iOS - ios

I am new to ios programming, I wanted to register notification center in the class, not in the view controller, I want to send some action from one view controller this custom class receives that action and it performs some view controller navigation.I wanted to have custom notification center in ios.
code:
NotificationCenter.default.post(name: Notification.Name(rawValue: "key"), object: nil)
class MainReceiver: NotificationCenter
{
override func post(name aName: NSNotification.Name, object anObject: Any?)
{
print("coming here")
}
}

Here you have snipped code:
class MainReceiver {
init() {
NotificationCenter.default.addObserver(self, selector: #selector(handleMethod(_:)), name: NSNotification.Name(rawValue: "Notification_Name"), object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
#objc func handleMethod(_ notification: Notification) {
// handle
}
}

From Apple's NSNotificationCenter documentation:
Each running Cocoa program has a default notification center. You typically don’t create your own.
I'm not sure why you think you want to create your own notification center, but trust me, you don't.
However, you can easily subscribe an object (an instance of a custom class, like you say you want to use) to notifications:
// let object = Whatever()
NotificationCenter.default.addObserver(object, selector: #selector(didReceive(notification:)), name: NSNotification.Name(rawValue: "key"), object: nil)
// object's didReceive(notification:) function will now be called when a notification with the specified name is posted. This can be posted from anywhere.
A while back, the function had to be decorated with the #objc attribute. I'm not sure if that's still the case, but if so, you'd use #objc func didReceive(notification: Notification) as your declaration in the receiving class.

If I understand your question correctly I think what you are looking for is the blocked based variant for the NotificationCenter.
You can find it in the official docs.
Example code from the docs:
let center = NSNotificationCenter.defaultCenter()
let mainQueue = NSOperationQueue.mainQueue()
self.localeChangeObserver = center.addObserverForName(NSCurrentLocaleDidChangeNotification, object: nil, queue: mainQueue) { (note) in
print("The user's locale changed to: \(NSLocale.currentLocale().localeIdentifier)")

Related

iOS unable to remove Notification observer. Deinit not getting called

I have a UIView similar to the one you can see below:
class ViewTaskViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
subscribeToNotifications()
}
func subscribeToNotifications() {
let notification = NotificationCenter.default
notification.addObserver(forName: Notification.Name(rawValue: "TimerUpdated"), object: nil, queue: nil, using: handleUpdateTimer)
print("Subscribed to NotificationCenter in ViewTaskViewController")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("TUFU TUFU TUFU")
NotificationCenter.default.removeObserver(self)
}
deinit {
print("DENINT")
}
#objc func handleUpdateTimer(notification: Notification) {
if let userInfo = notification.userInfo, let timeInSeconds = userInfo["timeInSeconds"] as? Int {
withUnsafePointer(to: &self.view) {
print("We got timeeeeee \(timeInSeconds) \($0)")
}
//do something here....
}
}
}
The issue I am having is that I am unable to remove the observers from this particular UIView when the user hits the back button and returns to another viewController.
ViewWillDisppear is called but deinit is not called. The strange thing is that if we remove subscribeToNotifications() from viewDidLoad() then the deinit is called.
The other issue is related to a memory leak. As you can see in the screenshot below, when the view does subscribe to notifications and the user leaves/re-enters the view, the memory usage increase.
Now compare that to when the subscribeToNotifications() is commented out, there is no increase in memory usage and only one instance of the viewController.
The conclusion is that there seems to be a correlation between the notification subscription creation of a new instance of the UIView hence the deinit is not being called.
I'd like to find out if there is a way we can deinitialize the view and unsubscribe from the notification.
Please let me know if you need further information. :)
I've found the removeObserver() only works if you use this version of addObserver()
notification.addObserver(self, selector:#selector(self.handleUpdateTimer), name: Notification.Name(rawValue: "TimerUpdated"), object: nil)
I'm guessing with the original version you aren't actually indicating who the observer is.
As #Spads said you can use
NotificationCenter.default.addObserver(self, selector: #selector(subscribeToNotifications), name: NSNotification.Name(rawValue: "TimerUpdate"), object: nil)
or the one you already have.
you can remove your notification by it's name or it's reference
NotificationCenter.default.removeObserver(self, name: "TimerUpdate", object: nil)
if you declared your notification at the top of your class then you can directly pass the reference of your notification to be removed in your case notification
NotificationCenter.default.removeObserver(notification)
You should store your newly added observer in a opaque object (NSObjectProtocol) and then call NotificationCenter.default.removeObserver(self.nameOfObserver)

How to use selector function from different class in iOS Swift, mainly for NotificationCenter

I am using Tab Bar Controller in an iOS app and I am using reachability for checking the network availability and for achieving it I am using Notifications.
The basic syntax of a notification in Swift 3 is as follows -
NotificationCenter.default.addObserver(observer: Any, selector: Selector, name: NSNotification.Name?, object: Any)
and things happen generally this way -
NotificationCenter.default.addObserver(observer: self, selector: #selector(ViewControllerName.functionName), name: NameOfTheNotification, object: nil)
What I want to do is -
I want to use a static function present in different class for selector i.e.., when this notification is generated I want to call the static function which is present in the different class.
let's say the class name is "Functions" and the name of function is "myFunction()"
in simple words what I want to do is whenever the notification is there I want to call myFunction() function from class Functions.
What I had tried
I had tried doing this but it doesn't help -
NotificationCenter.default.addObserver(observer: Functions(), selector: #selector(Functions.myFunction), name: NameOfTheNotification, object: nil)
There occurs an error and that error is as follows -
I had attached the Xcode snapshot below.
The easiest fix is to add #objc to reachabilityStatusChanged.
// ↓
#objc func reachabilityStatusChanged(notification: Notification) {
...
}
But NotificationCenter doesn't really require your class to support Objective-C. You could use the block variant of the method:
NotificationCenter.default.addObserver(forName: Notification.Name("ReachStatusChanged"), object: nil, queue: nil) { notification in
// do whatever Swift code with `notification` here.
// no need to add #objc anywhere.
reachabilityStatusChanged(notification)
}
The main problem you're experimenting here is the interoperability with obj-C.
Make sure you expose the function `reachabilityStatusChanged' to obj-C with the #objc annotation.
#objc func reachabilityStatusChanged
Also, make sure the class Functions is visible to obj-c. (Inheriting it from NSObject)
An illustration of why you have to retain Functions()
class Foo {
#objc func test() {
print("Hello")
}
}
var foo: Foo? = Foo()
let nc = NotificationCenter.default
nc.addObserver(foo!,
selector: #selector(Foo.test),
name: NSNotification.Name(rawValue: "Barrr"),
object: nil)
nc.post(name: NSNotification.Name(rawValue: "Barrr"), object: nil)
nc.post(name: NSNotification.Name(rawValue: "Barrr"), object: nil)
foo = nil
nc.post(name: NSNotification.Name(rawValue: "Barrr"), object: nil)
This will print Hello twice instead of three times because foo class was deallocated before the third call.

NotificationCenter not receiving posts

I have a class that accepts accelerometer data and posts it in a notification like so:
func notify(accel: accelPoint){
NotificationCenter.default.post(name: Notification.Name("newRawData"), object: nil)
}
And two objects set up to observe this, the first being a viewController:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(FirstViewController.newRawData), name: Notification.Name("newRawData"), object: nil)
Which calls the function:
func newRawData(notification: NSNotification){ ...
This works just fine.
The other observer is in a regular Swift class, instantiated in the app delegate. (I have tried doing this before and after creating the notifying class):
init(){
NotificationCenter.default.addObserver(self, selector: #selector(FilterManager.newRawData), name: Notification.Name("newRawData"), object: nil)
}
Which should call the function below but for some reason it does not.
#objc func newRawData(){
print("WHYYY")
}
The name this class is correct, and I have seen the the observer is being registered and the notifications are being posted so why isn't this class being notified like the other?
Also, why do I have to expose the newRawData function in the second class to objective-C but not the newRawData in the viewController class?
did you referenced FilterManager class in your AppDelegate? if not add this code in you AppDelegate class. also you can make FilterManger singleton to solve this problem.
var filterManger = FilterManager()

NotificationCenter Crash in Swift 3

Is it just me, or did NotificationCenter become a hot mess in Swift 3? :)
I have the following setup:
// Yonder.swift
extension Notification.Name {
static let preferenceNotification = Notification.Name("preferencesChanged")
}
// I fire the notification elsewhere, like this:
NotificationCenter.default.post(name: .preferenceNotification, object: nil)
In my first view controller, this works great:
// View Controller A <-- Success!
NotificationCenter.default.addObserver(self, selector: #selector(refreshData), name: .preferenceNotification, object: nil)
func refreshData() {
// ...
}
But this view controller:
//View Controller B <-- Crash :(
NotificationCenter.default.addObserver(self, selector: #selector(loadEntries(search:)), name: .preferenceNotification, object: nil)
func loadEntries(search:String?) {
// ...
}
...crashes with:
[NSConcreteNotification length]: unrecognized selector sent to instance
As far as I can tell, my observer is set up correctly. Any idea what I'm doing wrong?
Your issue is with your loadEntries(search:) method. It's not a valid signature. The selector used with Notification Center must either have no parameters or just one parameter. And if you have one parameter, that parameter will be the Notification object, not the notification name.
Your loadEntries needs to be:
func loadEntries(_ notification: NSNotification) {
// Optional check of the name
if notification.name == .preferenceNotification {
}
}
And the selector would need to be:
#selector(loadEntries(_:)) // or #selector(loadEntries)

How to call a function from a different view controller with different classes

When you press on the screen im trying to get a function that Is in a different view Controller to be called usaully i would just do the
viewControllerFuncIsIn().NameOfFunc()
but because the view controller class that has the function im trying to call is a SCNView. it gives me this error with ns coder because in currently in a Skscene
the function im trying to call is in a class called Extra1 right below the viewdidload(not in it).
Update for comment below:
Extra1(coder:NSCoder())!.see()
Small example for you:
Use delegate when connection is one to one.
Delegate:
Create protocol:
protocol TestViewControllerDelegate {
func finishTask(sender: TestViewController)
}
Create reference for delegation. It should be weak it is important.
weak var delegate:TestViewControllerDelegate?
Exited you're class.
extension MainViewController: TestViewControllerDelegate {
func finishTask(sender: TestViewController) {
}
}
Call delegate:
delegate?. finishTask(self)
Use notification when connection is one to many.
Notification:
Add observer for notification.
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ClassName.test), name:"NotificationIdentifier", object: nil)
Post notification.
NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)
I fond the answer to my question
func mySelector(elem: AnyObject) {
Extra1().see()
}
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.mySelector), name: "see", object: nil)
NSNotificationCenter.defaultCenter().postNotificationName("see", object: self)

Resources