Post of NSNotificationCenter causing "EXC_BAD_ACCESS" exception
Asked Answered
J

7

69

A UIViewController adds itself to the default center:

[[NSNotificationCenter defaultCenter]
 addObserver:self
 selector:@selector(editFood)
 name:@"editFood"
 object:nil];

Then a UITableView delegate NSObject posts a NSNotification:

[[NSNotificationCenter defaultCenter]
 postNotificationName:@"editFood"
 object:self];

During run time it get a EXC_BAD_ACCESS exception.

Is the defaultCenter getting released somewhere? The same concept works when I post a notification to a UIViewController from a UIViewController, but that shouldn't matter, right?

Jennee answered 14/4, 2011 at 19:41 Comment(2)
Where exactly is it crashing?Girosol
adding [[NSNotificationCenter defaultCenter] removeObserver:self] to -(void)dealloc{} method in your Scene will probably solve this problem for you. It worked for me; I was having the same problem you were. Good luck!Mistassini
P
131

One of your subscribers has been deallocated. Make sure to call [[NSNotificationCenter defaultCenter] removeObserver:self] in your dealloc (if not sooner).

Psychographer answered 14/4, 2011 at 19:44 Comment(5)
Thanks, I just realized my mistake (After looking at this and researching for four hours). The object I was attempting to reference after the call had been released. The debugger just made it look like that's where the EXC_BAD_ACCESS exception was being thrown.Jennee
@Paul: The Zombies instrument is really helpful in debugging this kind of problem.Aluminous
@Sven Thanks, I appreciate it. I actually tried using that once, and couldn't figure out how. I added an environment variable in the project plist, but that wouldn't work.Jennee
i'm releasing that object after notification called i got EXC_BAD_ACCESS how can i solve that?Rounds
EXC_BAD_ACCESS is not an exception, it's invalid memory accessLunalunacy
L
11

EXC_BAD_ACCESS can happen even after verifying dealloc exists like so:

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self]
}

The above will solve the problem most of the time, but apparently my cause was that I was indirectly adding the observer with a selector: set to nil as follows:

[NSNotificationCenter.defaultCenter addObserver:self
                                         selector:nil
                                             name:notificationName
                                           object:nil];

...so when I posted something with that notificationName, EXC_BAD_ACCESS occurred.

The solution was to send a selector that actually points to something.

Lallage answered 13/10, 2014 at 6:10 Comment(1)
Yup, just found this myself, I had put NULL as the selector intending it to be temporary, like oh let me go create that method, then I forgot to go update the selector param later (DOH) and yep, EXC_BAD_ACCESS result.Bloat
C
1

I had the same issue in Swift. The problem was the function target had a closure parameter with default value:

@objc func performFoo(completion: (() -> Void)? = nil) {
   ...
}

After I replace the closure parameter with a Notification parameter, it worked:

@objc func performFoo(notification: Notification) {
    ...
}

I had to make some refactor to make it works in a right way.

Catching answered 13/10, 2020 at 16:34 Comment(1)
Yes, the documentation for NotificationCenter addObserver(_:selector:name:object:) does state: "The method that aSelector specifies must have one and only one argument (an instance of NSNotification).".Trantrance
S
0

For anyone getting this error and using async/await, be sure to check if this other issue might not be the cause https://mcmap.net/q/281724/-swift-5-5-async-objc-didpulltorefresh-selector-crashes-app-with-error-exc_bad_access

tl;dr: at the time of writing @objc selectors and async methods don't go well together

Segregate answered 20/4, 2023 at 18:2 Comment(0)
T
0

With the introduction of async/await, be also careful for your selectors to not have the async keyword.

Tshombe answered 29/6, 2023 at 4:49 Comment(0)
V
0

This error can also occur with the wrong method header. I just got the error by not accepting an object when the notification was sending an object.

NotificationCenter.default.post(name: MyNotification.name, object: self)

Will work with:

@objc func myFunction(_ sender: AnyObject) {}

But not with

@objc func myFunction() {}

NOTE: This was edited to have the functions not be "async throws" which will cause a sporadic crash.

Viewfinder answered 28/8, 2023 at 1:59 Comment(2)
Yes, the documentation for NotificationCenter addObserver(_:selector:name:object:) does state: "The method that aSelector specifies must have one and only one argument (an instance of NSNotification).". And I'm not sure using an async throws method is a good idea for a function marked with @objc. See the more recent answers about that.Trantrance
You are right! This causes an intermittent crash. I had to change this from being async throws. Its deceptive because it doesn't crash every time.Viewfinder
F
0

Another possible reason: adding self as observer from an static method.

private static func listenToUpdates() {
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(updateNodesObjc),
        name: .itemProviderUpdated,
        object: nil
    )
}

Simple fix:

private func listenToUpdates() {
...
Flaggy answered 17/6 at 19:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.