Как использовать Reactive Cocoa с уведомлениями

Как я могу создать сигнал из имени уведомления? Например, я хочу перейти от:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(userDidChange:)
                                             name:kTTCurrentUserLoggedOffNotification
                                           object:nil];

на что-то вроде:

[signalForName(kTTCurrentUserLoggedOffNotification) subscribeNext:^(id x){
...
}];

person meisel    schedule 12.08.2013    source источник


Ответы (3)


-[NSNotificationCenter rac_addObserverForName:object:] возвращает бесконечный сигнал. Вы можете подписаться на него так

Цель-c

[[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil]
  takeUntil:[self rac_willDeallocSignal]]
  subscribeNext:^(id x) {
     NSLog(@"Notification received");
}];

Свифт

NSNotificationCenter.defaultCenter()
  .rac_addObserverForName(UIKeyboardWillShowNotification, object: nil)
  .takeUntil(self.rac_willDeallocSignal())
  .subscribeNext { (_) in
     print("Notification received")
  }

Этот сигнал, как указано, бесконечен. Если вам нужно, чтобы этот сигнал/подписка были привязаны ко времени жизни self, вы можете добавить takeUntil: с rac_willDeallocSignal следующим образом:

Цель-c

[[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil]
  takeUntil:[self rac_willDeallocSignal]]
  subscribeNext:^(id x) {
     NSLog(@"Notification received");
}];

Свифт

NSNotificationCenter.defaultCenter()
  .rac_addObserverForName(UIKeyboardWillShowNotification, object: nil)
  .takeUntil(self.rac_willDeallocSignal())
  .subscribeNext { (_) in
     print("Notification received")
  }
person hfossli    schedule 14.11.2013
comment
Это, кажется, работает, наверняка. Но если это приходится делать вот так, то метод в корне ошибочен. Сигналы живут до тех пор, пока на них есть ссылка. Если сигнал выпущен, то он должен быть утилизирован, что, в свою очередь, удаляет наблюдателя. Вы можете посмотреть в своем коде, там может быть сильная ссылка на сигнал, который удерживает его от освобождения. Или, если это не так, сообщите о проблеме в проект, поскольку, на мой взгляд, это не ожидаемое поведение. - person allprog; 14.11.2013
comment
@allprog Подписчики сохраняют свои сигналы до завершения, ошибки или утилизация. Вот почему бесконечные сигналы могут быть довольно грубыми. -takeUntil: — хорошее решение или что-то подобное, которое детерминировано завершает сигнал в определенной точке. - person Justin Spahr-Summers; 15.11.2013
comment
@JustinSpahr-Summers Спасибо за разъяснения. Я знал, что слишком хотел закричать на волка! Но ты здесь, чтобы поправить меня. :) Может ли документация содержать эти тонкости? Например. это бесконечный сигнал и указать на некоторое описание, которое показывает, что нужно принимать во внимание. Скажу честно, у фреймворка, кажется, есть некоторые из этих ловушек, и было бы лучше, если бы была подчеркнута специфика возвращаемого сигнала в этих случаях. - person allprog; 15.11.2013
comment
@allprog Это справедливое замечание. Написал проблему по этому поводу. - person Justin Spahr-Summers; 15.11.2013

В RACExtensions вы можете найти категорию NSNotificationCenter (RACSupport). Для этого есть метод:

- (RACSignal *)rac_addObserverForName:(NSString *)notificationName
                               object:(id)object;
person allprog    schedule 12.08.2013
comment
Я знаю, что это никогда не удаляется. Нужно ли нам самим распоряжаться этим сигналом? - person hfossli; 14.11.2013
comment
Наблюдение привязано к сигналу. Если это удалено, то наблюдатель удаляется. Может быть, вы где-то сильно ссылаетесь на сигнал? (Это сложная часть ObjC :)) - person allprog; 14.11.2013
comment
Узнал :) см. новый ответ - person hfossli; 14.11.2013

Swift версия с использованием ReactiveCocoa 4.1:

NSNotificationCenter.defaultCenter()
      .rac_addObserverForName(UIKeyboardWillShowNotification, object: nil)
      .takeUntil(self.rac_willDeallocSignal())
      .subscribeNext { (_) in
          print("UIKeyboardWillShowNotification")
      }
person Fabio    schedule 12.04.2016