Вы правы, когда говорите: «У меня нет селектора», потому что это уже половина дела. Вы можете получать уведомления из центра уведомлений без селектора, использующего Combine.
Другая половина заключается в том, что вы можете подтолкнуть свою логику для обработки уведомлений в конвейер объединения,так что правильный результат просто выскакивает из конца конвейера, если он вообще вас достигает.
Старомодный способ
Допустим, у меня есть представление карты, которое издает виртуальный визг, когдаоно прослушивается путем публикации уведомления:
static let tapped = Notification.Name("tapped")
@objc func tapped() {
NotificationCenter.default.post(name: Self.tapped, object: self)
}
Теперь, скажем, для целей примера, что игра заинтересована, когда она получает одно из этих уведомлений, является строковым значением name
Свойство Карты, на которой размещено уведомление. Если мы сделаем это старомодным способом, то получение этой информации будет двухэтапным процессом. Во-первых, нам нужно зарегистрироваться, чтобы получать уведомления вообще:
NotificationCenter.default.addObserver(self,
selector: #selector(cardTapped), name: Card.tapped, object: nil)
Затем, когда мы получаем уведомление, мы должны посмотреть, что его object
действительно является картой, и если это так,извлеките его свойство name
и сделайте с ним что-нибудь:
@objc func cardTapped(_ n:Notification) {
if let card = n.object as? Card {
let name = card.name
print(name) // or something
}
}
Способ объединения
Теперь давайте сделаем то же самое с помощью инфраструктуры объединения. Мы получаем издателя из центра уведомлений, вызывая его метод publisher
. Но мы не останавливаемся там. Мы не хотим получать уведомление, если object
не является картой, поэтому мы используем оператор compactMap
, чтобы безопасно перевести его на карту (и если это не карта, конвейер просто останавливается, как если быничего не случилось). Нам нужна только карта name
, поэтому мы используем оператор map
для ее получения. Вот результат:
let cardTappedCardNamePublisher =
NotificationCenter.default.publisher(for: Card.tapped)
.compactMap {$0.object as? Card}
.map {$0.name}
Допустим, что cardTappedCardNamePublisher
является свойством экземпляра нашего контроллера представления. Тогда у нас теперь есть свойство экземпляра, которое публикует строку, если карта отправляет уведомление tapped
, а в противном случае ничего не делает.
Вы понимаете, что я имею в виду, когда говорю, что логика выдвигается вконвейер?
Итак, как бы мы организовали получение того, что выходит из конца конвейера? Мы могли бы использовать приемник:
let sink = self.cardTappedCardNamePublisher.sink {
print($0) // the string name of a card
}
Если вы попробуете это, вы увидите, что теперь у нас возникает ситуация, когда каждый раз, когда пользователь нажимает на карту, печатается название карты. Это объединенный эквивалент нашего более раннего подхода «регистр-наблюдатель-с-селектором».