Reputation: 7129
I use 2 NSNotificationCenter
and in order to avoid retain cycles I've created a weakSelf like this: __unsafe_unretained AugmentedRealityViewController *weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
if (weakSelf.architectWorldNavigation.wasInterrupted) {
[weakSelf.architectView reloadArchitectWorld];
}
[weakSelf startWikitudeSDKRendering];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
[weakSelf stopWikitudeSDKRendering];
}];
The problem is that even if I remove them inside the dealloc
they keep getting fired and the app crashes.
Inside the dealloc
in order to remove the NSNotificationCenter
I use the following code:
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self.architectView removeFromSuperview];
}
It gets called when I leave the ViewController but the Notifications still works.. Can someone tell me what's wrong with the code and how to fix the problem?
Upvotes: 1
Views: 574
Reputation: 28409
In general, you are better off preferring the selector method of handling notifications. There are certainly good reasons for using the block based API, but your case seems tailor made for the other way.
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(applicationDidBecomeActiveNotification:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(applicationWillResignActiveNotification:)
name:UIApplicationWillResignActiveNotification
object:nil];
- (void)applicationDidBecomeActiveNotification:(NSNotification*)notification {
if (self.architectWorldNavigation.wasInterrupted) {
[self.architectView reloadArchitectWorld];
}
[self startWikitudeSDKRendering];
}
- (void)applicationWillResignActiveNotification:(NSNotification*)notification {
[self stopWikitudeSDKRendering];
}
Then, you can simply remove yourself, since you are the actual observer.
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Upvotes: 3
Reputation: 3690
It is because you are not adding self
to NSNotificationCenter
, you are adding the block
and then trying to remove self
When you are adding Block to NSNotificationCenter
it actually returns the object which you can use later to remove this code from NotificationCenter
__unsafe_unretained AugmentedRealityViewController *weakSelf = self;
self.becomeActiveHandler = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
if (weakSelf.architectWorldNavigation.wasInterrupted) {
[weakSelf.architectView reloadArchitectWorld];
}
[weakSelf startWikitudeSDKRendering];
}];
self.willResignActiveHandler = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
[weakSelf stopWikitudeSDKRendering];
}];
and then in dealloc , you can remove these handlers
[[NSNotificationCenter defaultCenter] removeObserver:self.becomeActiveHandler];
[[NSNotificationCenter defaultCenter] removeObserver:self.willResignActiveHandler];
Upvotes: 1
Reputation: 7552
1) Remove the __unsafe_unretained
attribute. It may not be hurting, but it's not doing anything useful.
2) You are not capturing the return value from [NSNotificationCenter addObserverForName:object:queue:usingBlock:]
, which means you have no way to unregister for the notifications. This method creates a proxy object that listens to the notification and runs the block. If you don't hold on to a reference and unregister at some point, you have a memory leak and a notification handler that you don't need.
Upvotes: 1