NotificationCenter throw error when adding observer with selector function - ios

In the server side I use socket.io library to send some JS object data type through, upon users typing in their devices:
var typingUsers = {};
clientSocket.on("startType", function(clientNickname){
typingUsers[clientNickname] = 1;
io.emit("userTypingUpdate", typingUsers);
});
when the app receives data, it will post notification:
private func listenForOtherMessages() {
socket.on("userTypingUpdate") { (dataArray, socketAck) -> Void in
NotificationCenter.default.post(name:NSNotification.Name(rawValue: "userTypingNotification"), object: dataArray[0] as! [String: AnyObject])
}
}
And then the notification is added to a view controller as an observer:
NotificationCenter.default.addObserver(self, selector: Selector(("handleDisconnectedUserUpdateNotification:")), name: NSNotification.Name(rawValue: "userWasDisconnectedNotification"), object: nil)
This implementation always throw an error "unrecognised selector send to ..."
But the following implementation without a selector works ok:
NotificationCenter.default.addObserver(forName:NSNotification.Name(rawValue: "userTypingNotification"), object: nil, queue: nil){ object in
print(object)
}
It seems like I cannot add an selector to the observer, I think the problems might lie in the object data type, but I cannot really figure out why..

found the answer:
NotificationCenter.default.addObserver(self, selector: #selector(self.userTypingNotification), name: NSNotification.Name(rawValue: "userWasDisconnectedNotification"), object: nil)
older post

Related

NotificationCenter obersever not called in swift 4

i am trying to post notification NotificationCenter from appdelegate and receive notification in another view but notification not received.
Post notification :-
func xmppStream(_ sender: XMPPStream, didReceive message: XMPPMessage)
{
print("did receive message isss-->\(message)")
NotificationCenter.default.post(name: Notification.Name("MessageReceived"), object: message)
}
Received Notification in viewdidload :-
NotificationCenter.default.addObserver(self, selector: #selector(self.messagereceived(notification:)), name: Notification.Name("MessageReceived"), object: nil)
Method :-
#objc func messagereceived(notification:Notification)
{
let message = notification.object as? XMPPMessage
print("chat conversion message is----->\(message)")
}
My "messagereceived" Method not called.
so any one have solution related to this then please help me.
Thanks in advance.
Change the notification post from
NotificationCenter.default.post(name: Notification.Name("MessageReceived"), object: message)
to
NotificationCenter.default.post(Notification(name: Notification.Name(rawValue: "MessageReceived"),object: message))
and the observer from
NotificationCenter.default.addObserver(self, selector: #selector(self.messagereceived(notification:)), name: Notification.Name("MessageReceived"), object: nil)
to
NotificationCenter.default.addObserver(self, selector: #selector(self.messagereceived(notification:)), name: NSNotification.Name(rawValue: "MessageReceived"), object: nil)
In my case i can't get NotificationCenter in some situation in my app .
and problem was that using
NotificationCenter.default.addObserver(self, selector: #selector(btnRegister(_:)), name: Notification.Name(rawValue: "btnRegister"), object: nil)
in my viewDidLoad() func, And when i set above code in my viewWillAppear() func, that's work perfectly.
According to your code logic , move above code to other func or other section of your code and try to fix your problem.

removeObserver for Notification Swift3

I have a strange issue. I register and unregister my Notification like so:
func doRegisterNotificationListener() {
NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: "RateAlertRated"), object: nil, queue: nil, using: rateDidRate)
}
func doUnregisterNotificationListener() {
NotificationCenter.default.removeObserver(self, name: Notification.Name(rawValue: "RateAlertRated"), object: nil)
}
func rateDidRate(notification: Notification) {
let rating = notification.userInfo?["score"] as? Int
let message = notification.userInfo?["message"] as? String
let response = Response(rating: rating, message: message)
output.presentRated(response)
}
This view controller is in a UITabBarController. doRegisterNotificationListener is called in viewDidAppear and doUnregisterNotificationListener is called in viewDidDisappear. When I switch between tabs the register and unregister methods are being called correctly (I tested using a print statement). However if I fire a notification it will still be received even though doUnregisterNotificationListener was called last. Any ideas what I might be doing wrong here?
Quick note:
Also tried:
NotificationCenter.default.removeObserver(self)
This also doesn't work.
I have tested your code and once i register observer with this type it is not called when you doUnregister it. please try this.
NotificationCenter.default.addObserver(self, selector: #selector(rateDidRate(notification:)), name: Notification.Name(rawValue: "RateAlertRated"), object: nil)
If you are working with addObserver(forName:object:queue:using:) you should remove it in this way:
Create:
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)")
}
Remove:
center.removeObserver(self.localeChangeObserver)
This approach is taken from the documentation.

NSNotificationCenter doesn't send message in Swift

I use Core Spotlight, and I use UIPageController as RootViewController and several UIViewControllers. Every controller has UIView I drawing a circle of information in there. When I slide between controllers and open new controller I sent NSNotification from current UIViewController to current UIView which is located on current UIViewController. I sent NSNotification that so turn on NSTimer in UIView for updating of information. It works is fine when I just open the app. My problem is when I find infromation from the app in spotlight search and open needed controller from spotlight search NSNotification doesn't sent. I tried several different methods and I cannot to find how I can to make it. Please tell me how can I make it?
UPDATE I also tried singleton pattern for NSNotificationCenter but it also didn't help me.
UPDATE I tried write Selector as notificationCenter.addObserver(self, selector: Selector(turnOnMemoryTimer()), name: "turnOnMemoryArc", object: nil)
and it works when I launch app from spotlight search but it doesn't work when I just launch the app. For any help on this matter thanks!
I also tried to send notification from AppDelegate but it also didn't work
switch startIndex {
case 1:
notificatioCenter.postNotificationName("turnOnCPUTimer", object: nil)
default: break
}
UIViewController
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
if GlobalTimer.sharedInstance.controllerTimer != nil {
GlobalTimer.sharedInstance.controllerTimer.invalidate()
GlobalTimer.sharedInstance.viewTimer.invalidate()
}
GlobalTimer.sharedInstance.controllerTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "showMemory", userInfo: nil, repeats: true)
// notifications
notificationCenter.postNotificationName("turnOnMemoryArc", object: nil) // this message doesn't sent
if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
notificationCenter.postNotificationName("checkMemoryOrientation", object: nil)
notificationCenter.addObserver(self, selector: "changeMemoryOrientation", name: UIDeviceOrientationDidChangeNotification, object: nil)
}
}
UIView
// MARK: - var and let
var arc = Arc()
let notificationCenter = NSNotificationCenter.defaultCenter()
var boolForMemoryArc = false
override func drawRect(rect: CGRect) {
if boolForMemoryArc == false {
drawMemoryArc()
boolForMemoryArc = true
}
notificationCenter.addObserver(self, selector: "turnOnMemoryTimer", name: "turnOnMemoryArc", object: nil)
notificationCenter.addObserver(self, selector: "changedMemoryOrientation", name: "checkMemoryOrientation", object: nil)
}
func turnOnMemoryTimer() {
if GlobalTimer.sharedInstance.viewTimer != nil {
GlobalTimer.sharedInstance.viewTimer.invalidate()
}
GlobalTimer.sharedInstance.viewTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "drawMemoryArc", userInfo: nil, repeats: true)
}
I had a similiar issue and solved it like this:
notificationCenter.addObserver(self, selector: "turnOnMemoryTimer:", name: "turnOnMemoryArc", object: nil)
Receive AnyObject:
func turnOnMemoryTimer(notification: AnyObject) {
}
This needed change happened "spontaneous" the normal code was working for months.
I think you need to add the NSNotification as parameter to the function you're calling. So, two tweeks:
notificationCenter.addObserver(self, selector: "turnOnMemoryTimer:", name: "turnOnMemoryArc", object: nil)
and
func turnOnMemoryTimer(notification: NSNotification) {
// function body
}

NSNotification breaking in Swift when trying to pass back userInfo

I'm having issues trying to pass back userInfo via postNotification in Swift. What's strange is the code only breaks when I try to use userInfo -- if I post a notification with no data to a selector with no parameters, everything works. But when I try to pass back userInfo, I get a "unrecognized selector sent to instance" error. So something's wrong with my selector signature in my ViewController, but I can't figure out what.
Here is the code that breaks:
In my table view
let data = ["selection": selectedOption]
dismissViewControllerAnimated(true, completion: {NSNotificationCenter.defaultCenter().postNotificationName(wordsetPickedNotification, object: self, userInfo: data)})
In my view controller:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "wordsetPicked", name: wordsetPickedNotification, object: nil)
...
func wordsetPicked(n:NSNotification) {
//do stuff
}
Change selector: "wordsetPicked" to selector: "wordsetPicked:".

NSNotificationCenter addObserver in Swift

How do you add an observer in Swift to the default notification center? I'm trying to port this line of code that sends a notification when the battery level changes.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryLevelChanged:) name:UIDeviceBatteryLevelDidChangeNotification object:nil];
Swift 4.0 & Xcode 9.0+:
Send(Post) Notification:
NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)
OR
NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil, userInfo: ["Renish":"Dadhaniya"])
Receive(Get) Notification:
NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
Function-Method handler for received Notification:
#objc func methodOfReceivedNotification(notification: Notification) {}
Swift 3.0 & Xcode 8.0+:
Send(Post) Notification:
NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)
Receive(Get) Notification:
NotificationCenter.default.addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
Method handler for received Notification:
func methodOfReceivedNotification(notification: Notification) {
// Take Action on Notification
}
Remove Notification:
deinit {
NotificationCenter.default.removeObserver(self, name: Notification.Name("NotificationIdentifier"), object: nil)
}
Swift 2.3 & Xcode 7:
Send(Post) Notification
NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)
Receive(Get) Notification
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(_:)), name:"NotificationIdentifier", object: nil)
Method handler for received Notification
func methodOfReceivedNotification(notification: NSNotification){
// Take Action on Notification
}
For historic Xcode versions...
Send(Post) Notification
NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)
Receive(Get) Notification
NSNotificationCenter.defaultCenter().addObserver(self, selector: "methodOfReceivedNotification:", name:"NotificationIdentifier", object: nil)
Remove Notification
NSNotificationCenter.defaultCenter().removeObserver(self, name: "NotificationIdentifier", object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self) // Remove from all notifications being observed
Method handler for received Notification
func methodOfReceivedNotification(notification: NSNotification) {
// Take Action on Notification
}
Annotate either the class or the target method with #objc
#objc private func methodOfReceivedNotification(notification: NSNotification) {
// Take Action on Notification
}
// Or
dynamic private func methodOfReceivedNotification(notification: NSNotification) {
// Take Action on Notification
}
It's the same as the Objective-C API, but uses Swift's syntax.
Swift 4.2 & Swift 5:
NotificationCenter.default.addObserver(
self,
selector: #selector(self.batteryLevelChanged),
name: UIDevice.batteryLevelDidChangeNotification,
object: nil)
If your observer does not inherit from an Objective-C object, you must prefix your method with #objc in order to use it as a selector.
#objc private func batteryLevelChanged(notification: NSNotification){
//do stuff using the userInfo property of the notification object
}
See NSNotificationCenter Class Reference, Interacting with Objective-C APIs
A nice way of doing this is to use the addObserver(forName:object:queue:using:) method rather than the addObserver(_:selector:name:object:) method that is often used from Objective-C code. The advantage of the first variant is that you don't have to use the #objc attribute on your method:
func batteryLevelChanged(notification: Notification) {
// do something useful with this information
}
let observer = NotificationCenter.default.addObserver(
forName: NSNotification.Name.UIDeviceBatteryLevelDidChange,
object: nil, queue: nil,
using: batteryLevelChanged)
and you can even just use a closure instead of a method if you want:
let observer = NotificationCenter.default.addObserver(
forName: NSNotification.Name.UIDeviceBatteryLevelDidChange,
object: nil, queue: nil) { _ in print("🔋") }
You can use the returned value to stop listening for the notification later:
NotificationCenter.default.removeObserver(observer)
There used to be another advantage in using this method, which was that it doesn't require you to use selector strings which couldn't be statically checked by the compiler and so were fragile to breaking if the method is renamed, but Swift 2.2 and later include #selector expressions that fix that problem.
Declare a notification name
extension Notification.Name {
static let purchaseDidFinish = Notification.Name("purchaseDidFinish")
}
You can add observer in two ways:
Using Selector
NotificationCenter.default.addObserver(self, selector: #selector(myFunction), name: .purchaseDidFinish, object: nil)
#objc func myFunction(notification: Notification) {
print(notification.object ?? "") //myObject
print(notification.userInfo ?? "") //[AnyHashable("key"): "Value"]
}
or using block
NotificationCenter.default.addObserver(forName: .purchaseDidFinish, object: nil, queue: nil) { [weak self] (notification) in
guard let strongSelf = self else {
return
}
strongSelf.myFunction(notification: notification)
}
func myFunction(notification: Notification) {
print(notification.object ?? "") //myObject
print(notification.userInfo ?? "") //[AnyHashable("key"): "Value"]
}
Post your notification
NotificationCenter.default.post(name: .purchaseDidFinish, object: "myObject", userInfo: ["key": "Value"])
from iOS 9 and OS X 10.11. It is no longer necessary for an
NSNotificationCenter observer to un-register itself when being
deallocated. more info
For a block based implementation you need to do a weak-strong dance if you want to use self inside the block. more info
Block based observers need to be removed more info
let center = NSNotificationCenter.defaultCenter()
center.removeObserver(self.localeChangeObserver)
Swift 3.0 in Xcode 8
Swift 3.0 has replaced many "stringly-typed" APIs with struct "wrapper types", as is the case with NotificationCenter. Notifications are now identified by a struct Notfication.Name rather than by String. See the Migrating to Swift 3 guide.
Previous usage:
// Define identifier
let notificationIdentifier: String = "NotificationIdentifier"
// Register to receive notification
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(_:)), name: notificationIdentifier, object: nil)
// Post a notification
NSNotificationCenter.defaultCenter().postNotificationName(notificationIdentifier, object: nil)
New Swift 3.0 usage:
// Define identifier
let notificationName = Notification.Name("NotificationIdentifier")
// Register to receive notification
NotificationCenter.default.addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification), name: notificationName, object: nil)
// Post notification
NotificationCenter.default.post(name: notificationName, object: nil)
All of the system notification types are now defined as static constants on Notification.Name; i.e. .UIDeviceBatteryLevelDidChange, .UIApplicationDidFinishLaunching, .UITextFieldTextDidChange, etc.
You can extend Notification.Name with your own custom notifications in order to stay consistent with the system notifications:
// Definition:
extension Notification.Name {
static let yourCustomNotificationName = Notification.Name("yourCustomNotificationName")
}
// Usage:
NotificationCenter.default.post(name: .yourCustomNotificationName, object: nil)
In Swift 5
Let's say if want to Receive Data from ViewControllerB to
ViewControllerA
ViewControllerA (Receiver)
import UIKit
class ViewControllerA: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//MARK: - - - - - Code for Passing Data through Notification Observer - - - - -
// add observer in controller(s) where you want to receive data
NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
}
//MARK: - - - - - Method for receiving Data through Post Notificaiton - - - - -
#objc func methodOfReceivedNotification(notification: Notification) {
print("Value of notification : ", notification.object ?? "")
}
}
ViewControllerB (Sender)
import UIKit
class ViewControllerB: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//MARK: - - - - - Set data for Passing Data Post Notification - - - - -
let objToBeSent = "Test Message from Notification"
NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)
}
}
Pass Data using NSNotificationCenter
You can also pass data using NotificationCentre in swift 3.0 and NSNotificationCenter in swift 2.0.
Swift 2.0 Version
Pass info using userInfo which is a optional Dictionary of type [NSObject : AnyObject]?
let imageDataDict:[String: UIImage] = ["image": image]
// Post a notification
NSNotificationCenter.defaultCenter().postNotificationName(notificationName, object: nil, userInfo: imageDataDict)
// Register to receive notification in your class
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: notificationName, object: nil)
// handle notification
func showSpinningWheel(notification: NSNotification) {
if let image = notification.userInfo?["image"] as? UIImage {
// do something with your image
}
}
Swift 3.0 Version
The userInfo now takes [AnyHashable:Any]? as an argument, which we provide as a dictionary literal in Swift
let imageDataDict:[String: UIImage] = ["image": image]
// post a notification
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: imageDataDict)
// `default` is now a property, not a method call
// Register to receive notification in your class
NotificationCenter.default.addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: NSNotification.Name(rawValue: "notificationName"), object: nil)
// handle notification
func showSpinningWheel(_ notification: NSNotification) {
if let image = notification.userInfo?["image"] as? UIImage {
// do something with your image
}
}
Source pass data using NotificationCentre(swift 3.0) and NSNotificationCenter(swift 2.0)
Swift 5 Notification Observer
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(batteryLevelChanged), name: UIDevice.batteryLevelDidChangeNotification, object: nil)
}
#objc func batteryLevelChanged(notification : NSNotification){
//do here code
}
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(self, name: UIDevice.batteryLevelDidChangeNotification, object: nil)
}
I'm able to do one of the following to successfully use a selector - without annotating anything with #objc:
NSNotificationCenter.defaultCenter().addObserver(self,
selector:"batteryLevelChanged:" as Selector,
name:"UIDeviceBatteryLevelDidChangeNotification",
object:nil)
OR
let notificationSelector: Selector = "batteryLevelChanged:"
NSNotificationCenter.defaultCenter().addObserver(self,
selector: notificationSelector,
name:"UIDeviceBatteryLevelDidChangeNotification",
object:nil)
My xcrun version shows Swift 1.2, and this works on Xcode 6.4 and Xcode 7 beta 2 (which I thought would be using Swift 2.0):
$xcrun swift --version
Apple Swift version 1.2 (swiftlang-602.0.53.1 clang-602.0.53)
This is very simple example of custom notification observer and post
Add Notification Observer
NotificationCenter.default.addObserver(self, selector: #selector(myFunction), name: Notification.Name("CustomeNotificationName"), object: nil)
Add Selector and handle Observer call
#objc func myFunction(notification: Notification) {
//Write you code
}
Post Notification(Observer) when it is required.
NotificationCenter.default.post(name: NSNotification.Name("CustomeNotificationName"), object: "Object", userInfo: ["key":"Value"])
Notes:- Make user when you leave screen you need to remove observer. e.g.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self);
}
Create an objc function which you want to execute when notification is called.
#objc func reloadNotification(_ notification: Notification) {
tblview.reloadData()
}
Add the notification observer in view did load.
NotificationCenter.default.addObserver(self, selector:#selector(reloadNotification(_:)), name: Notification.Name("reloadSideMenuDataNS"),object: nil)
post your notification where you want to call the function.
NotificationCenter.default.post(name: Notification.Name("reloadSideMenuDataNS"), object: nil)
you can remove your notification in view did disappear with below.
NotificationCenter.default.removeObserver(self, name: Notification.Name("reloadSideMenuDataNS"), object: nil)
In swift 2.2 - XCode 7.3, we use #selector for NSNotificationCenter
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(rotate), name: UIDeviceOrientationDidChangeNotification, object: nil)
We should remove notification also.
Ex.
deinit
{
NotificationCenter.default.removeObserver(self, name:NSNotification.Name(rawValue: "notify"), object: nil)
}
In swift 3, Xcode 8.2:- checking battery state level
//Add observer
NotificationCenter.default.addObserver(self, selector: #selector(batteryStateDidChange), name: NSNotification.Name.UIDeviceBatteryStateDidChange, object: nil)
//Fired when battery level changes
func batteryStateDidChange(notification: NSNotification){
//perform manipulation here
}
NSNotificationCenter add observer syntax in Swift 4.0 for iOS 11
NotificationCenter.default.addObserver(self, selector: #selector(keyboardShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
This is for keyboardWillShow notification name type. Other type can be selected from the available option
the Selector is of type #objc func which handle how the keyboard will show ( this is your user function )
Swift 5 & Xcode 10.2:
NotificationCenter.default.addObserver(
self,
selector: #selector(batteryLevelDidChangeNotification),
name: UIDevice.batteryLevelDidChangeNotification,
object: nil)

Resources