Need to call removeObserver twice - ios

I have a view that observe values of itself on init like this :
[self addObserver:self forKeyPath:#"focusPointOfInterestIndicator" options:0 context:kSRCameraViewObserverContext];
[self addObserver:self forKeyPath:#"exposurePointOfInterestIndicator" options:0 context:kSRCameraViewObserverContext];
[self addObserver:self forKeyPath:#"paused" options:0 context:kSRCameraViewObserverContext];
[self addObserver:self forKeyPath:#"previewLayerGravity" options:0 context:kSRCameraViewObserverContext];
And on dealloc, observers are removed as they should be like this :
[self removeObserver:self forKeyPath:#"focusPointOfInterestIndicator"];
[self removeObserver:self forKeyPath:#"exposurePointOfInterestIndicator"];
[self removeObserver:self forKeyPath:#"paused"];
[self removeObserver:self forKeyPath:#"previewLayerGravity"];
But unless calling it twice (with or without context, doesn't change anything), I have a crash when the view is deallocated cause the value are still observed.
But I'm quite sure observers are added only once (since it's in init of object).
I just wonder if why it could be registered twice ? Or is it like by calling it twice, it let to the object to effectively remove observers ? If someone have any clue ?

init is the primary initializer of NSObjet that means init must be called in Apple's implementation of initWithCoder / initWithFrame with something like [super init];
so your sharedSetup is called twice
EDIT (thanks to And Ainu):
To be more specific, that's the init method of UIView which calls the initWithFrame method.

Its good practice if you use try catch every time you remove the observer.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
#try {
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"LocationSelected" object:nil];
} #catch (id anException){
//do nothing, obviously it wasn't attached because an exception was thrown
}
[[NSNotificationCenter defaultCenter] addObserverForName:#"LocationSelected" object:nil queue:[NSOperationQueue mainQueue] usingBlock: ^(NSNotification *not) {
//Someone posted the notification handle it here
}];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
#try {
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"LocationSelected" object:nil];
} #catch (id anException){
//do nothing, obviously it wasn't attached because an exception was thrown
}
}

One more thing you can do is instead of observing in init method replace the same in loadView or awakeFromNib method. Then it will not called twice.

Related

The NSNotificationCenter is never executed

This is my code.
Here create the observer to Notification called Example into ViewController
- (void)addObserverExample
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(example:)
name:#"Example"
object:nil];
}
- (void)example:(NSNotification *)notification{
NSLog(#"Example!!!");
}
From viewDidLoad register my observer
- (void)viewDidLoad
{
[self addObserverExample];
}
In my second ViewController. When tapped a button excute this code:
[[NSNotificationCenter defaultCenter] postNotificationName:#"Example" object:self.dictKeys userInfo:nil];
The problem I have is that the notification is never executed.
Any idea.
Have created demo for NSNotificationCenter as per your question and it's working fine for me. Here it is the link of that code: NSNotificationCenter Demo
- (void)viewDidLoad {
[super viewDidLoad];
[self addObserverExample];
}
- (void)addObserverExample
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(example:)
name:#"Example"
object:nil];
}
- (void)example:(NSNotification *)notification{
NSLog(#"Example!!!");
NSLog(#"%#",notification.userInfo);
}
- (IBAction)btnFireNotification:(id)sender {
[[NSNotificationCenter defaultCenter] postNotificationName:#"Example" object:nil userInfo:#{#"key" : #"value"}];
}
I believe the problem you're having may be related to the fact that in your second view controller, you're passing self.dictKeys in the object parameter.
If you want to pass data via the NSNotificationCenter, you should use the userInfo parameter instead.
Darshan's example does this the correct way.

iOS - awakeFromNib of UITableViewCell gets called when an NSNotification is received

NSNotification observers are added when awakeFromNib is called in my UITableViewCell. Then, I am removing the observers when removeFromSuperView is called.
- (void)awakeFromNib
{
[super awakeFromNib];
[self setNotificationObserver];
_vHolder.layer.cornerRadius = 10.0f;
_vHolder.layer.shadowColor = [UIColor blackColor].CGColor;
_vHolder.layer.shadowRadius = 2.0f;
_vHolder.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
_vHolder.layer.shadowOpacity = 0.5f;
}
- (void)removeFromSuperview
{
[super removeFromSuperview];
[self removeNotificationObserver];
}
- (void)setNotificationObserver
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didReceiveESSMQTTMessageNotification:) name:NOTIF_ESSMQTT_MESSAGE_RECEIVED object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didReceiveDeviceStatesMessageNotification:) name:NOTIF_DEVICE_STATES_RECEIVED object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didReceiveDeviceOnOffStateNotification:) name:NOTIF_DEVICE_ON_OFF_STATE_RECEIVED object:nil];
}
- (void)removeNotificationObserver
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:NOTIF_ESSMQTT_MESSAGE_RECEIVED object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NOTIF_DEVICE_STATES_RECEIVED object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NOTIF_DEVICE_ON_OFF_STATE_RECEIVED object:nil];
}
I am using NSNotification to refresh states of my buttons and images within this UITableViewCell.
The problem I am facing is, every time an NSNotication is received, the awakeFromNib is called. This will cause the states of my buttons and images to refresh back to its initial states. The strange thing is, I never saw removeFromSuperview getting called before that.
So my questions are:
Why is awakeFromNib getting called when NSNotification is received?
I am just wondering, is adding observer under awakeFromNib the correct thing to do when you want your UITableViewCells to observe NSNotifications? (Well, I've been doing this all the time.)
Because your cell was refreshed content but did not be remove from superview
You had to call removeNotificationObserver when content of cell was refreshed successfully.
I suggest you using protocol instead of notification.
Hope help.

iOS Exception of adding NSNotificationCenter to a UIView

I added a NSNotificationCenter to a UIView, when I first go to the page, the NSNotificationCenter work fine.
However, when I left that page and back to that page again, it will give out error
'NSInvalidArgumentException', reason: '-[UITextMagnifierTimeWeightedPoint updateProfile:]: unrecognized selector sent to instance.
Here are the code.
UIView1 :
- (void)changeUIView {
UIView2 *view = [[UIView2 alloc] init];
// show UIView2
}
UIView2 :
- (id)init {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updateProfile:) name:#"updateProfile" object:nil];
return self;
}
-(void)updateProfile:(NSNotification *)notification {
// do something
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:#"updateProfile"];
}
- (void)buttonClick {
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateProfile" object:nil userInfo:nil];
}
You need to remove self as the observer not the selector you are using to handle the notification
[[NSNotificationCenter defaultCenter] removeObserver:self];
Or if you want to be specific you can use
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"updateProfile" object:nil];
Always
Add NSNotificationCenter in viewDidAppear
And
Remove NSNotificationCenter in viewDidDisAppear

UIKeyboard notification handler triggered 3 times

My code:
-(void)viewWillAppear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleKeyboard:) name:UIKeyboardWillChangeFrameNotification object:nil];
}
-(void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-(void)handleKeyboard:(NSNotification*)notification {
NSLog(#"triggered");
}
See:
The disappearing handler is triggered once as normal, but 3 times when appears. Is this a iOS bug?
Possibly not helpful for your problem but you need to be calling [super viewWill… for your overrides.
-(void)viewWillAppear:(BOOL)animated
-(void)viewWillDisappear:(BOOL)animated
From the docs.
If you override this method, you must call super at some point in
your implementation.

Slow response using NSNotification defaultCenter

Hi I am using NSNotificationCenter defaultCenter to implement the 'like' and 'comment' functions in my app.
//In Answer Table View
#implementation AnswerTableView
- (id)initWithParentController:(UIViewController *)pController andResourcePath:(NSString *)thisResourcePath {
....
// Notification to reload table when a comment is submitted
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reloadTable)
name:#"Comment Submitted"
object:nil];
// Notification to reload table when an answer is liked
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reloadTable)
name:#"Answer Liked"
object:nil];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
//In custom button implementation - THIS BUTTON IS CREATED IN EVERY CELL OF THE TABLEVIEW
#implementation UICustomButton
-(id)initWithButtonType:(NSString *)type {
self = [super init];
if (self) {
//Initialization done here
}
return self;
}
- (void)buttonPressed {
if ([btnType isEqualToString:#"like"]) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"Answer Liked" object:nil];
}
else if ([btnType isEqualToString:#"comment"]) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"Comment Submitted" object:nil];
}
}
However, I realize that after using these functions for a while, the response speed of the table reload gets slower and slower (to a point where it crashes).
Did I miss out anything in the implementation i.e. deallocating etc
You are repeatedly adding observers and the slowdown occurs because the notification code has to cycle over more and more observers to send notifications. You are probably crashing because you are leaking so many of these views.
Put a log statement in your dealloc to see if these instances are ever cleaned up. Also there can be timing issues with removeObserver in a dealloc method. try to remove the observer before dealloc if you can.
Sometimes its good to queue the event with Grand Central Dispatch to make sure its running on the main thread.
dispatch_async(dispatch_get_main_queue()

Resources