NSNotifications и removeObserver в UIView

Я создаю подкласс UIView:

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

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

Вызов делегата должен отображать UIView и возвращает UIView, который я использую для отключения фоновых касаний (просто UIView с черным черным фоном и уменьшенной альфой).

В подклассе UIView я добавляю уведомления клавиатуры:

-(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
}

Я пытаюсь удалить NSNotifications в dealloc:

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

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

Проблема в том, что dealloc срабатывает сразу после 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

Все они срабатывают с разницей в 0,1 секунды. Подкласс UIView ведет себя именно так, как я хочу; Он показывает, все его содержимое работает, и я могу removeFromSuperview без проблем.

Я исходил из предположения, что dealloc сработает, когда все ссылки на подкласс UIView достигнут 0?

Я использую АРК.

Что я делаю неправильно?

РЕДАКТИРОВАТЬ:

Выяснил, что я делаю неправильно:

-(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;
}

Поэтому я создаю свое представление с помощью метода init, который загружает файл xib. awakeFromNib срабатывает, а затем объект, который я создаю с помощью моего файла init, теряет ссылку и освобождается, в то время как объект, созданный из awakeFromNib, отображается.

Как я могу это исправить? Или я делаю что-то принципиально неправильное и создаю разрыв в пространственно-временном континууме?

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>>

person Padin215    schedule 12.06.2013    source источник
comment
ваше предположение верно, но на основе опубликованного кода я не вижу, кому принадлежит ваш подкласс uiview.   -  person oiledCode    schedule 13.06.2013
comment
В вызове делегата, который я делаю (displayEntityForm:), добавляется представление: [mainView addSubview:benefentialsView]`. Не приведет ли это к собственности?   -  person Padin215    schedule 13.06.2013
comment
да, но это не тот код, который вы разместили, а также почему вы добавляете наблюдателя в подкласс?   -  person oiledCode    schedule 13.06.2013
comment
Я попытался добавить переменную класса @property (strong, nonatomic) BeneficialsFormView *beneficialView; и назначить ее, но проблема все еще есть.   -  person Padin215    schedule 13.06.2013
comment
и вы делаете self.beneficialView = [[BeneficialsFormView alloc] init];   -  person oiledCode    schedule 13.06.2013
comment
Да (по-другому): BeneficialsFormView *view = [[BeneficialsFormView alloc] init];, а затем self.beneficialView = view.   -  person Padin215    schedule 13.06.2013
comment
[self.delegate displayEntityForm: представление]; это тот метод, который в конце делает addSubview? а также кто является делегатом?   -  person oiledCode    schedule 13.06.2013
comment
да. вызов делегата displayEntityForm:view добавляет представление. Вызов делегата передается через другой подкласс UIView в UIViewController, который добавляет представление к его основному представлению.   -  person Padin215    schedule 13.06.2013
comment
не могли бы вы попытаться стать владельцем этого представления в делегате   -  person oiledCode    schedule 13.06.2013
comment
Хорошо, я попытался, но не решил проблему.   -  person Padin215    schedule 13.06.2013


Ответы (2)


Вы слишком все усложняете. Просто поступайте с этим просто:

1.) Загрузить базовый вид

2.) Проверьте критерии того, нужно ли отображать представление, чтобы отключить фоновые касания.

3.) Если это так, просто наложите градиент как подвид. Удалите наблюдатель NSNotificationCenter, когда пользователь нажимает кнопку, чтобы выйти из представления. НЕ удаляйте его внутри Dealloc. Это часто задерживается, и вы увидите эту же проблему.

person Tommy Devoy    schedule 12.06.2013
comment
Хорошо, это кажется жизнеспособным решением. Я предполагаю, что основная проблема заключается в том, что код создает 2 экземпляра объекта; один раз в методе init (который сразу освобождается) и один раз в методе awakeFromNib, который вызывается из метода init. - person Padin215; 13.06.2013

Я искал ответ на аналогичный вопрос, я нашел два метода, с помощью которых мы можем добавлять и удалять наблюдателя. Просто чтобы показать обновленные API для тех, кто ищет это.

Это вызывается перед добавлением представления в окно. Он также будет вызываться при удалении представления из своего окна.

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

Ниже метод вызывается сразу после установки его свойства окна.

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