Swift Nsnotificationcenter post notification error - ios

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)

Related

-[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

NSNotification issue - unrecognized selector sent to instance

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]

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)

Error: Unrecognised Selector when using class reference

I have a class in a swift file called cloud I use a reference to that class in my project to call two of its methods. But I get the following error and the app crashes;
NSForwarding: warning: object 0x7fc938717160 of class 'App.Cloud' does
not implement methodSignatureForSelector: -- trouble ahead
Unrecognized selector -[App.Cloud persistentStoreWillChange]
(lldb)
Does anybody know who i could resolve this and why this is occurring ?
PS: The error only appears when installing the app and launching for the first time. If I quit and relaunch it does not appear, however it does not execute the methods.
Heres my class,
class Cloud {
let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
func persistentStoreWillChange (notification:NSNotification) {
self.moc!.performBlock { () -> Void in
if self.moc!.hasChanges {
var error:NSError? = nil
self.moc!.save(&error)
if error != nil {
println("Save error: \(error)")
} else{
// drop any manged object refrences
self.moc!.reset()
}
}
}
}
func persistentStoreDidChange () {
println("Store Did Change")
}
//Refresh Data
func recieveChanges (notification:NSNotification){
self.moc!.performBlock { () -> Void in
self.moc!.mergeChangesFromContextDidSaveNotification(notification)
}
}
//View Will Appear
func addObsevers() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "persistentStoreDidChange:", name: NSPersistentStoreCoordinatorStoresDidChangeNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("persistentStoreWillChange:"), name:NSPersistentStoreCoordinatorStoresWillChangeNotification, object: moc!.persistentStoreCoordinator)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("recieveICloudChanges:"), name:NSPersistentStoreDidImportUbiquitousContentChangesNotification, object: moc!.persistentStoreCoordinator)
}
//View Will Dissapear
func removeObservers() {
NSNotificationCenter.defaultCenter().removeObserver(self, name: NSPersistentStoreCoordinatorStoresDidChangeNotification, object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: NSPersistentStoreCoordinatorStoresWillChangeNotification, object: moc!.persistentStoreCoordinator)
NSNotificationCenter.defaultCenter().removeObserver(self, name: NSPersistentStoreDidImportUbiquitousContentChangesNotification, object: moc!.persistentStoreCoordinator)
}
}
Class reference in View Controller:
let iCloudSync = Cloud()
override func viewWillAppear(animated: Bool) {
iCloudSync.addObsevers()
loadData()
}
override func viewWillDisappear(animated: Bool) {
iCloudSync.removeObservers()
}
You need to derive class Cloud from NSObject when you declare it, like this:
class Cloud : NSObject {
Otherwise your selectors are invisible to Objective-C.
You changed code but you forgot to change method declaration from
func persistentStoreDidChange () {
println("Store Did Change")
}
to
func persistentStoreDidChange (notification: NSNotification) {
println("Store Did Change")
}
Well you do this, which says to call persistentStoreDidChange on self when the notification triggers:
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "persistentStoreDidChange",
name: NSPersistentStoreCoordinatorStoresDidChangeNotification,
object: nil)
But then it looks like you don't implement persistentStoreDidChange within class Cloud.
So either remove that observer, or implement the method.
Your methods have parameters so you must express this with ':' in their names. Changed code should look like this:
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("persistentStoreWillChange:"), name: NSPersistentStoreCoordinatorStoresWillChangeNotification, object: moc!.persistentStoreCoordinator)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("recieveICloudChanges:"), name: NSPersistentStoreDidImportUbiquitousContentChangesNotification, object: moc!.persistentStoreCoordinator)

Resources