Эта статья была первоначально опубликована на iOS Geek Community .
Сегодня давайте поговорим о том, как и почему мы используем NSNotification
для передачи данных и связи / уведомления между классами и структурами. Кстати, NSNotification
, в отличие от своего названия, не имеет ничего общего с Push Notification — ошибкой новичка 101 (я).
Да, в Swift есть много способов передачи данных: Delegate
, Key-Value Observing
, Segue
и NSNotification
, Target-Action
, Callbacks
. Однако у каждого есть свои плюсы и минусы. Они как столовая посуда. Например, я бы не использовал палочки для еды — хотя это чертовски хорошо — пить суп.
Поскольку их много, я расскажу только по одной за раз, и я упомяну, почему вы должны ложки вместо палочек по пути. Нет смысла рассказывать о различиях между палочками для еды и ножами, прежде чем я использую оба.
Что я думаю, вы узнаете
В этом уроке вы узнаете 2 вещи. Во-первых, вы поймете, как «уведомлять» другие контроллеры представления или внутри одного контроллера представления. Во-вторых, вы поймете силу NSNotification
и его слабые стороны.
UI Component
Есть два вида контроллеров. FirstVC
и SecondVC
. Я предполагаю, что вы уже знаете, как встроить UINavigationController
и подключить IBOutlets
и IBActions
и так далее.
SecondVC
уведомит FirstVC
. Когда я говорю «уведомить», это все равно что тыкать. Это не отправка каких-либо данных, но, конечно, мы можем. Я объясню, как отправить данные чуть позже в этой статье. Пример ниже аналогичен тому, как пользователь обновляет профиль в Facebook или Instagram. Я не использую UITableView
так как это было бы излишним для объяснения концепции.
Прежде чем мы начнем, давайте представим, как бы мы реализовали это на очень высоком уровне. Представьте, что два viewcontrollers похожи на красивую пару. У них обоих есть смартфоны (объекты NSNotification), чтобы общаться друг с другом. Во-вторых, каждый смартфон имеет две функции: получение и отправка данных . Наконец, чтобы найти устройство друг друга, у них есть общий секретный ключ . Тем не менее, решать друг другу, хочет ли кто-нибудь ответить на звонок или просто проигнорировать.
Поскольку у нас есть общее понимание того, как они общаются друг с другом, давайте погрузимся в Swift
Сначала мы собираемся хранить секретный ключ. Вы можете создать отдельный файл Swift или просто создать его вне любого контроллера вида, подобного этому.
import UIKit let myNotificationKey = "com.bobthedeveloper.notificationKey" class SecondVC: UIViewController {}
myNotificationKey
будет использоваться для соединения этих смартфонов вместе. Конечно, как и некоторые другие пары, вы можете иметь более одного ключа для любых целей.
Теперь пришло время прикрепить смартфон. Давайте назовем это наблюдателем. Наблюдатель будет иметь четыре параметра. Он спросит Observer
который будет self
так как вы SecondVC
смартфон к SecondVC
. Во-вторых, Selector
, это функция, которая запускается при уведомлении. В-третьих, имя, которое относится к секретному коду. Наконец, object
который я объясню позже при работе с FirstVC. Просто положите nil
на данный момент.
class SecondVC: UIViewController { @IBOutlet weak var secondVCLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(doThisWhenNotify), name: NSNotification.Name(rawValue: myNotificationKey), object: nil) } func doThisWhenNotify() { print("I've sent a spark!") } }
Я не понимаю значения свойства type по default
потому что в руководстве по API нет описания. Это говорит, *
«Обзор недоступен» — Apple
В любом случае, у SecondVC
есть смартфон / наблюдатель, пора отправлять / уведомлять, когда нажимается кнопка
@IBAction func tabToNotifyBack(_ sender: UIButton) { NotificationCenter.default.post(name: Notification.Name(rawValue: myNotificationKey), object: self) secondVCLabel.text = "Notification Completed!" }
В этом контексте object
относится к отправителю. Поскольку SecondVC
уведомляет себя, он self
.
Поскольку FirstVC
еще не зарегистрировал наблюдателя, искра / тыкание не повлияет на него. Я уже упоминал ранее, партнер имеет право поднять трубку или просто проигнорировать. В iOS мы назвали это «слабой связью». В отличие от отправки данных между контроллерами представления с использованием делегата / протокола, не происходит сумасшедшего связывания. Я знаю, что некоторые из вас, ребята, в замешательстве. Я планирую написать статью о том, как передавать данные с использованием делегата в будущем. Также я буду обсуждать delegate vs NSNotification
Ресурс
Передача данных между ViewControllers в Swift 3 без Segue ( YouTube )
Время получать
FirstVC
довольно прост. Он добавит смартфон и прислушивается к искре, если у него такой же секретный ключ.
import UIKit class FirstVC: UIViewController { @IBOutlet weak var FirstVCLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(doAfterNotified), name: NSNotification.Name(rawValue: myNotificationKey), object: nil) } func doAfterNotified() { print("I've been notified") FirstVCLabel.text = "Damn, I feel your spark" } }
Теперь поговорим об object
который является одним из параметров, которые я пропустил ранее. Если он равен nil
, вам все равно, откуда / куда смартфон отправляет данные, пока у вас есть секретный ключ. Я никогда ничего не использовал
кроме nil
так что, возможно, те, кто использовал его раньше, могут мне помочь. Другими словами, я не знаю, как реализовать
Теперь это должно выглядеть примерно так.
Кстати, представьте, что SecondVC
— это как Facebook вживую. Пока есть много других контроллеров представления, которые содержат наблюдателей, которые слушают секретный ключ, он может уведомить множество людей. Однако это делается синхронно . Для тех, кто не понимает, что это значит, задача выполняется по одному, одновременно блокируя любые другие действия, пока задача не будет выполнена. Таким образом, это замедлит работу устройств, если будет слишком много контроллеров представления. (не уверен, сколько это слишком много).
Исходный код
Github
Передача данных
Теперь вы научились уведомлять . Давайте быстро научимся отправлять данные при уведомлении. Это законно Вот где происходит настоящее волшебство.
В SecondVC
вместо старого доброго способа
// Pass Spark NotificationCenter.default.post(name: NSNotification.Name(rawValue: myNotificationKey), object: nil)
Теперь вы можете отправить искру, которая содержит словарь
// Pass Data NotificationCenter.default.post(name: NSNotification.Name(rawValue: myNotificationKey), object: nil, userInfo: ["name":"Bob"])
В FirstVC
, под viewDidLoad
, вы вставите это вместо
NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: myNotificationKey), object: nil, queue: nil, using:catchNotification)
Я не собираюсь говорить об queue
. Если поставить nil
, задача получения происходит синхронно. Другими словами, если это не nil
, FirstVC
может получать данные с помощью Grand Central Dispatch
. Если вы не понимаете GCD, не волнуйтесь. Я написал две статьи для вас. Может быть, я должен написать о том, как передавать данные асинхронно с помощью GCD! Это было бы интересно.
Ресурсы
Введение в Grand Central Dispatch в Свифте 3 ( Средний )
Интерфейс и сеть, как босс в Swift 3 ( средний )
Вы заметили что-то другое. Это верно catchNotification
Эта функция будет использовать искру, которая содержит userInfo!
catchNotification
выглядит примерно так
func catchNotification(notification:Notification) -> Void { guard let name = notification.userInfo!["name"] else { return } FirstVCLabel.text = "My name, \(name) has been passed! " }
Как только кнопка из SecondVC
нажата, catchNotification
запускается автоматически и содержит userInfo
переданный из SecondVC
. Если вы не понимаете, как разворачивать опциональные файлы, используя инструкцию охраны, не стесняйтесь проверить мое видео ниже.
Ресурс
Охранное заявление ( YouTube )
Итак, наконец, это должно выглядеть примерно так
Ресурс
Исходный код
Удалить Обозреватель / Смартфон
Если вы хотите удалить любого наблюдателя, когда представление было отклонено, просто вставьте приведенный ниже код в FirstVC
или любые другие контроллеры представления.
override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(true) NotificationCenter.default.removeObserver(self) }
Последние замечания
Эта статья заняла немного больше времени, чем я ожидал. Но так приятно писать и общаться с большим количеством людей. Спасибо всем за то, что прошли весь путь ко дну Очень признателен.
Рекомендуемые статьи :
Не стесняйтесь проверить рекомендуемые статьи: