68

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?

Alex Cio
  • 6,014
  • 5
  • 44
  • 74
Paul Jordan
  • 681
  • 1
  • 5
  • 3
  • Where exactly is it crashing? – Till Apr 14 '11 at 19:47
  • 3
    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! – nodebase Sep 22 '14 at 02:05

6 Answers6

131

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

Ben Scheirman
  • 40,531
  • 21
  • 102
  • 137
  • 3
    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. – Paul Jordan Apr 14 '11 at 19:51
  • 4
    @Paul: The Zombies instrument is really helpful in debugging this kind of problem. – Sven Apr 14 '11 at 19:59
  • @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. – Paul Jordan Apr 14 '11 at 20:44
  • i'm releasing that object after notification called i got EXC_BAD_ACCESS how can i solve that? – jpd Mar 06 '13 at 05:39
  • 3
    EXC_BAD_ACCESS is not an exception, it's invalid memory access – junglecat Oct 21 '13 at 09:16
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.

kraftydevil
  • 5,144
  • 6
  • 43
  • 65
  • 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. – Billy Gray Oct 20 '14 at 14:52
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.

pableiros
  • 14,932
  • 12
  • 99
  • 105
  • 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)."*. – HangarRash Aug 28 '23 at 06:25
0

For anyone getting this error and using async/await, be sure to check if this other issue might not be the cause https://stackoverflow.com/a/76066999/2828729

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

aclima
  • 630
  • 1
  • 11
  • 20
0

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

Vladimir
  • 521
  • 5
  • 16
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.

arc4randall
  • 3,275
  • 3
  • 27
  • 40
  • 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)."*. 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. – HangarRash Aug 28 '23 at 06:23
  • 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. – arc4randall Aug 28 '23 at 19:59