NSNotification issue - unrecognized selector sent to instance - ios

I have this observer
NotificationCenter.default.addObserver(self, selector: #selector(flashButtonDidPress(_:)), name: NSNotification.Name(rawValue: "flash"), object: nil)
And this delegate function
func flashButtonDidPress(_ title: String) {
cameraController.flashCamera(title)
}
Can someone explain me why I have the following error?
unrecognized selector sent to instance
Thanks in advance
EDIT:
I am also accessing the function without the use of a notification

NotificationCenter sends Notifications, not Strings, use a second function to be called from somewhere else:
func flashButtonDidPress(_ notification: Notification) {
if let title = notification.userInfo?["title"] as? String {
flashCamera(with:title)
}
}
func flashCamera(with title: String)
{
cameraController.flashCamera(title)
}
pass the title in the userInfo dictionary when posting the notification, e.g.
let userInfo = ["title", title]

Related

Accessing ViewController's method in custom Class

I have made a func in ViewController, that can receive a string and change the title of a label, that is located on screen.
Here it is:
func setNewTitleForMainLabelOnScreen(text: String){
mainLabelOnScreen.cell?.title = text
}
What i want to do, is to call this function (viewController's method?) from another class.
Like that:
class MainLabelEditor{
func updateLabelOnScreen{
ViewController.setNewTitleForMainLabelOnScreen(text: "Hello")
}
}
Unfortunately, it doesn't work.
Here is what xcode says:
If I press return, it shows this:
The question is, how do i call setNewTitleForMainLabelOnScreen from MainLabelEditor?
I usually use NotificationCenter to deliver data from other ViewController.
ViewController
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(setNewTitleForMainLabelOnScreen), name: NSNotification.Name(rawValue: "changeTitle"), object: nil)
}
#objc func setNewTitleForMainLabelOnScreen(_ notification: Notification){
mainLabelOnScreen.cell?.title = notification.object as! String
}
: Specifies the value passed to NotificationCenter object as title.
Other UIViewController
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "changeTitle"), object: "titleTextValue")
: You can add the string value you want as the title to the object.
You can try:
public class func setNewTitleForMainLabelOnScreen(text: String){
mainLabelOnScreen.cell?.title = text
}
So it turns out, all you need to do is to type
ViewController().setNewTitleForMainLabelOnScreen(text: "Hello")
instead of
ViewController.setNewTitleForMainLabelOnScreen(text: "Hello")

-[NSConcreteNotification count]: unrecognized selector sent to instance 0x2816dd380

Took me an hour to figure this iOS crash out, posting the solution in case it helps.
You might have a different value other than count after NSConcreteNotification in your crash.
I was crashing on accessing an array.count, which is why it's count in my case:
#objc fileprivate func loadParts(constraints: [NSLayoutConstraint]? = nil) {
assert(Thread.current.isMainThread)
var constraints = constraints ?? [NSLayoutConstraint]()
...
let cCount = constraints.count
I could not for the life of me see how it could crash on constraints.count as the array is guaranteed to exist.
I was wiring this function up to a Notification like this:
NotificationCenter.default.addObserver(self, selector: #selector(self.loadParts), name: UIDevice.batteryStateDidChangeNotification, object: nil)
If you look at the documentation for addObserver, it says the function must have exactly one parameter which is a Notification. What was happening was that my function was being called with a Notification, but my code expected it to be an array.
The fix was to create a new function that simply called the function I wanted (loadParts), and have the Notification hit that instead:
NotificationCenter.default.addObserver(self, selector: #selector(self.loadPartsNotification(_:)), name: UIDevice.batteryStateDidChangeNotification, object: nil)
...
#objc fileprivate func loadPartsNotification(_ notification: Notification) {
self.loadParts()
}
fileprivate func loadParts(constraints: [NSLayoutConstraint]? = nil) {
...

Must Selector method be in the same instances as where the observer is?

Normally, the code addObserver both the Selector method tag with #Objc are coded in the same instance (instantiated class).
It is possible to pass a Selector from different instance to the addObserver?
The reason for doing this is because Selector behavior as a callback most of the time. Some of the callback methods are commonly used and could well be coded into a CommonCallBack Class, an example of usage would be like this:
class SomeViewController{
override func viewDidLoad() {
...
let common = CommonCallback()
NotificationCenter.default.addObserver(
self,
selector: #selector(common.methodA),
name: "notificationName",
object: nil
)
}
}
class CommonCallback{
#Objc func methodA() {
// doing A
}
}
The issue is I keep getting unrecognized selector sent to instance
You can also achieve this by doing this way
class SomeViewController {
override func viewDidLoad() {
let common = CommonCallback()
common.enableObserver = true
}
}
class CommonCallback{
var enableObserver : Bool!
override func viewDidLoad() {
if enableObserver {
NotificationCenter.default.addObserver(
self,
selector: #selector(common.methodA),
name: "notificationName",
object: nil
)
}
}
#objc func methodA() {
// Your code here
}
}
I found out, where went wrong if the code. The observer argument must be in the same class as the Selector method, so instead of:
NotificationCenter.default.addObserver(
self,
selector: #selector(common.methodA),
name: "notificationName",
object: nil
)
it should be:
NotificationCenter.default.addObserver(
common,
selector: #selector(common.methodA),
name: "notificationName",
object: nil
)
This will call CommonCallback.methodA instead of SomeViewController.methodA

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)

Swift Nsnotificationcenter post notification error

I have a problem with post notification function.
In the FirstViewController in viewDidLoad I have this sentence:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "ponresultado", name: "resultadobusqueda", object: nil)
After that I have the function:
func ponresultado(notification:NSNotification)
{
var oDato : oDatoSel = notification.object as oDatoSel
}
In second view controller of type TableViewController in didDeselectRowAtIndexPath method I have this code:
var oDato : oDatoSel = oDatoSel()
oDato.id = "1"
oDato.nombre = "test"
NSNotificationCenter.defaultCenter().postNotificationName("resultadobusqueda", object: oDato)
I receive this error:
[App.FirstViewController ponresultado]: unrecognized selector sent to instance 0x797d2310
If in my ponresultado function in FirstViewController, I quit notification:NSNotification parameter like this:
func ponresultado()
{
var oDato : oDatoSel = notification.object as oDatoSel
}
I don't have the error. Why?
You need to add a : after the selector's name:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "ponresultado:", name: "resultadobusqueda", object: nil)
As your method is declared such as it accepts a NSNotification object:
func ponresultado(notification:NSNotification)
{
var oDato : oDatoSel = notification.object as oDatoSel
}
If your method takes a NSNotification as a parameter, you should add the ":" to your selector when registering. So your line :
NSNotificationCenter.defaultCenter().addObserver(self, selector: "ponresultado", name: "resultadobusqueda", object: nil)
Becomes
NSNotificationCenter.defaultCenter().addObserver(self, selector: "ponresultado:", name: "resultadobusqueda", object: nil)

Resources