简体   繁体   中英

NSNotifications and removeObserver in a UIView

I create a subclassed UIView :

BeneficialsFormView *view = [[BeneficialsFormView alloc] init];
view.alpha = 0;
view.delegate = self;

view.screenView = [self.delegate displayEntityForm:view];

The delegate call is to display the UIView and returns a UIView that I use to disable background touches (just a UIView with black blackground color and reduced alpha).

In the subclassed UIView , I add in keyboard notifications:

-(void)awakeFromNib {
    DLog(@"fired");

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardEvent:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardEvent:) name:UIKeyboardWillHideNotification object:nil];

    // UI Code
}

I try to remove the NSNotifications in dealloc :

-(void)dealloc {
    DLog(@"fired");

    [[NSNotificationCenter defaultCenter] removeObserver:self forKeyPath:UIKeyboardWillShowNotification];
    [[NSNotificationCenter defaultCenter] removeObserver:self forKeyPath:UIKeyboardWillHideNotification];
}

The issue is that dealloc is fired right after awakeFromNib :

2013-06-12 15:37:39.260  DEBUG | -[BeneficialsFormView init] | fired
2013-06-12 15:37:39.287  DEBUG | -[BeneficialsFormView awakeFromNib] | fired
2013-06-12 15:37:39.339  DEBUG | -[BeneficialsFormView dealloc] | fired

They all are fired withing .1 seconds of each other. The subclassed UIView behaves exactly as I want it to; It shows, all its contents work and I can removeFromSuperview w/out issues.

I was under the assumption dealloc would fire when all references to the subclassed UIView reached 0?

I am using ARC.

What am I doing wrong?

EDIT:

Found out what I'm doing wrong:

-(id)init {
    DLog(@"fired");
    DLog(@"self: %@",self);

    self = [super init];

    if (self) {
        self = [[[NSBundle mainBundle] loadNibNamed:@"BeneficialsFormView" owner:self options:nil] objectAtIndex:0];
    }

    return self;
}

So I create my view with my init method, which loads the xib file. awakeFromNib fires and then the object I create with my init file looses reference and is deallocated while the objected created from awakeFromNib is displayed.

How can I fix this? Or am I doing something fundamentally wrong and creating a tear in the space-time continuum?

2013-06-12 18:15:33.957  DEBUG | -[BeneficialsFormView init] | fired
2013-06-12 18:15:33.959  DEBUG | -[BeneficialsFormView init] | self: <BeneficialsFormView: 0x1f0b1d50; frame = (0 0; 0 0); transform = [0, 0, 0, 0, 0, 0]; alpha = 0; opaque = NO; layer = (null)>

2013-06-12 18:15:33.988  DEBUG | -[BeneficialsFormView awakeFromNib] | fired
2013-06-12 18:15:33.989  DEBUG | -[BeneficialsFormView awakeFromNib] | self: <BeneficialsFormView: 0x1e58da60; frame = (0 0; 350 400); autoresize = RM+BM; layer = <CALayer: 0x1e5c60f0>>

2013-06-12 18:15:34.044  DEBUG | -[BeneficialsFormView dealloc] | fired
2013-06-12 18:15:34.045  DEBUG | -[BeneficialsFormView dealloc] | self: <BeneficialsFormView: 0x1f0b1d50; frame = (0 0; 0 0); layer = <CALayer: 0x1f0d4830>>

You're making it too complicated. Just go simple with it:

1.) Load base view

2.) Check criteria for whether you need to display the view to disable background touches

3.) If so, just overlay the gradient as a subview. Remove the NSNotificationCenter observer when a user presses a button to leave the view. Do NOT remove it inside of dealloc. It is often delayed and you will see this same problem occur.

I was looking for an answer for the similar question,i found two methods where we can add and remove observer. Just to show the updated APIs,for them who are looking for this.

This is called before the view is added to to a window. It also will be called when the view is removed from its window.

- (void)willMoveToWindow:(UIWindow *)newWindow {
    if (newWindow == nil) {
        [[NSNotificationCenter defaultCenter] removeObserver:
                                                        name:
                                                      object:];
     }
}

Below method is called immediately after its window property gets set.

-(void)didMoveToWindow {
        if (self.window) {
            [[NSNotificationCenter defaultCenter] addObserver:
                                                     selector: 
                                                         name:
                                                       object:];
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM